在Haskell中“重用”参数的伎俩?

时间:2010-12-02 10:24:40

标签: haskell coding-style pointfree

我偶尔会偶然发现我想表达的问题“请使用两次最后一次参数”,例如为了写无点样式或避免lambda。 E.g。

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)

如果有这样的函数,我可以写这个代码无点:

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这样的东西,所以我想我可能会错过这里的伎俩或成语。

3 个答案:

答案 0 :(得分:29)

来自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

哦,对于你的无意义的例子,您是否尝试过使用应用符号(来自Control.Applicative):

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

(我也不知道为什么人们如此喜欢a ++ (x:b)而不是a ++ [x] ++ b ......它不会更快 - 内联商会照顾它 - 后者是如此更加对称!哦,好吧)

答案 1 :(得分:11)

你所谓的'doubleArgs'通常被称为dup - 它是W组合子(在模拟鸟模拟中称为鸣鸟) - “基本复制器”。

你所谓的'dup'实际上就是'starling-prime'组合。

Haskell有一个相当小的“组合基础”参见Data.Function,加上一些Applicative和Monadic操作凭借Applicative和Monad的函数实例添加更多“标准”组合器(&lt; *&gt; from Applicative是S - 用于功能实例的starling组合器,liftA2&amp; liftM2是starling-prime)。社区似乎没有太多的热情来扩展Data.Function,所以虽然组合器非常有趣,但实际上我更喜欢在组合器不能直接使用的情况下长时间使用。

答案 2 :(得分:9)

以下是我问题第二部分的另一种解决方案:箭头!

import Control.Arrow

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

&&&(“扇出”)将参数分配给两个函数并返回结果对。 >>>(“然后”)反转函数应用程序顺序,它允许从左到右进行一系列操作。 second仅适用于一对的第二部分。当然,你需要一个uncurry来在一个期望两个参数的函数中提供该对。