我偶尔会偶然发现我想表达的问题“请使用两次最后一次参数”,例如为了写无点样式或避免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这样的东西,所以我想我可能会错过这里的伎俩或成语。
答案 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
来在一个期望两个参数的函数中提供该对。