2010-12-02 36 views
19

偶尔我会偶然发现我想表达的问题,“请使用最后一个参数两次”,例如为了写无点式或避免lambda。例如。欺骗“重复使用”参数在Haskell中?

sqr x = x * x 

可以写成

sqr = doubleArgs (*) where 
    doubleArgs f x = f x x 

或者考虑这个稍微复杂功能(从this question拍摄):如果有类似的功能

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs) 

我可以写这个代码pointfree此:

ins x = dup (zipWith (\ a b -> a ++ (x:b))) inits tails where 
    dup f f1 f2 x = f (f1 x) (f2 x) 

但是由于我无法在Hoogle中找到类似doubleArgs或dup的东西,所以我想我可能会在这里错过一个技巧或习惯用法。

回答

26

Control.Monad

join :: (Monad m) -> m (m a) -> m a 
join m = m >>= id 

instance Monad ((->) r) where 
    return = const 
    m >>= f = \x -> f (m x) x 

扩大:

join :: (a -> a -> b) -> (a -> b) 
join f = f >>= id 
     = \x -> id (f x) x 
     = \x -> f x x 

所以,是的,Control.Monad.join

哦,你pointfree例如,你有没有尝试过使用应用性符号(从Control.Applicative):

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails 

(我也不知道为什么人们这么喜欢a ++ (x:b)代替a ++ [x] ++ b ...它不是更快 - 内联会照顾它 - 而后者是更对称的!哦)

+2

而根据`pointfree`,`dup`可以算作'liftM2`。我真的需要更好地处理函数的monad实例。 – 2010-12-02 10:30:43

+2

谢谢你们提供甚至**两种**方法来解决这些问题。顺便说一句我试过`sqr =(*)<$> id <*> id`,它也适用:-) – Landei 2010-12-02 10:57:34

11

你称为'doubleArgs'更经常被称为dup - 它是W combinator(称为莺在模仿一只知更鸟) - “基本复印机”。

你所说的'dup'其实就是'starling-prime'组合子。

Haskell具有相当小的“组合基础”参见Data.Function,再加上一些Applicative和Monadic操作,通过Applicative和Monad的函数实例添加更多“标准”组合器(Applicative的< *>是S - starling combinator为功能实例,liftA2 & liftM2是starling-prime)。在扩展Data.Function的时候,社区似乎没有太多的热情,所以虽然combinator是好玩的,但实际上我更喜欢在combinator不直接可用的情况下长期使用。

7

这是我的问题的第二部分的另一个解决方案:箭头!

import Control.Arrow 

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++)) 

&&&(“扇出”)分配一个参数两个功能,并返回对结果。 >>>(“然后”)反转功能应用程序的顺序,从而允许从左到右具有一系列操作。 second只适用于一对的第二部分。当然,你最后需要一个uncurry来为一对函数提供两个参数。