在Haskell中"重用"参数的伎俩?

Lan*_*dei 21 haskell coding-style pointfree

我不时偶然发现我想要表达的问题"请使用两次最后一个参数",例如为了编写无点样式或避免使用lambda.例如

sqr x = x * x
Run Code Online (Sandbox Code Playgroud)

可写成

sqr = doubleArgs (*) where
   doubleArgs f x = f x x
Run Code Online (Sandbox Code Playgroud)

或者考虑这个稍微复杂的功能(取自这个问题):

ins x xs = zipWith (\ a b -> a ++ (x:b)) (inits xs) (tails xs)
Run Code Online (Sandbox Code Playgroud)

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

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

但是因为我在Hoogle中找不到像doubleArgs或dup这样的东西,所以我猜我可能会错过这里的伎俩或成语.

luq*_*qui 30

来自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
Run Code Online (Sandbox Code Playgroud)

拓展:

join :: (a -> a -> b) -> (a -> b)
join f = f >>= id
       = \x -> id (f x) x
       = \x -> f x x
Run Code Online (Sandbox Code Playgroud)

所以,是的,Control.Monad.join.

哦,对于你的无意义的例子,你尝试过使用applicative notation(from Control.Applicative):

ins x = zipWith (\a b -> a ++ (x:b)) <$> inits <*> tails
Run Code Online (Sandbox Code Playgroud)

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

  • 根据`pointfree`,`dup`可以说是"liftM2".我真的需要更好地处理函数的monad实例. (2认同)
  • 谢谢你们两个****方法来解决这些问题.顺便说一下,我试过`sqr =(*)<$> id <*> id`,它也可以运行:-) (2认同)
  • @Antal SZ:真的没有那么多 - 只是一个易于使用内联的轻量级阅读器monad.第一个参数作为环境,`fmap`和`return`与你期望的环境无关.等我最喜欢的用途是使用条件组合子`(<?>)`,可以像`even <?>(\`div \`2)<*>(+ 1)`我认为它比`\n - >更易读,如果甚至是n,那么`div` 2除了n + 1`.(nb - `liftM2(\ bte - > if b then t else e)`会产生两个分支的副作用,尽管这与'Reader`无关) (2认同)

ste*_*ley 12

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

你称之为'dup'的实际上就是'starling-prime'组合.

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

  • 哦,我找到了Haskell的"鸟类操作员":http://hackage.haskell.org/packages/archive/data-aviary/0.2.3/doc/html/Data-Aviary-Birds.html (2认同)
  • @Landei - 我认为它们是"仅供参考",即我不建议在工作代码中依赖它们.我应该让Cabal描述更明确,他们只是"参考",但我还没有完成它. (2认同)
  • @Landei称之为"dup"的东西也被称为[J中的"动词叉"](http://www.jsoftware.com/help/jforc/forks_hooks_and_compound_adv.htm),它由运算符的简单并置编写,例如`(fgh)x`而不是`dup fghx`. (2认同)

Lan*_*dei 9

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

import Control.Arrow

ins x = inits &&& tails >>> second (map (x:)) >>> uncurry (zipWith (++))
Run Code Online (Sandbox Code Playgroud)

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