“重用”的技巧Haskell 中的争论?

发布于 2024-10-05 09:38:08 字数 704 浏览 7 评论 0原文

有时我会偶然发现我想要表达的问题“请使用最后一个参数两次”,例如为了编写 pointfree 风格或避免 lambda。例如

sqr x = x * x

可以写成

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

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

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)

但是因为我找不到像 doubleArgs 或 dup 这样的东西Hoogle,所以我想我可能会错过这里的一个技巧或习语。

From time to time I stumble over the problem that I want to express "please use the last argument twice", e.g. in order to write pointfree style or to avoid a lambda. E.g.

sqr x = x * x

could be written as

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

Or consider this slightly more complicated function (taken from this question):

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

I could write this code pointfree if there were a function like this:

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

But as I can't find something like doubleArgs or dup in Hoogle, so I guess that I might miss a trick or idiom here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

深海少女心 2024-10-12 09:38:08

来自 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)) <
gt; inits <*> tails

我也不知道为什么人们如此喜欢 a ++ (x: b) 而不是 a ++ [x] ++ b...它并不更快——内联函数会处理它——而且后者更加对称!那好吧)

From 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

Expanding:

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

So, yeah, Control.Monad.join.

Oh, and for your pointfree example, have you tried using applicative notation (from Control.Applicative):

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

(I also don't know why people are so fond of a ++ (x:b) instead of a ++ [x] ++ b... it's not faster -- the inliner will take care of it -- and the latter is so much more symmetrical! Oh well)

初相遇 2024-10-12 09:38:08

你所谓的“doubleArgs”更常被称为 dup - 它是 W 组合器(在《模仿一只知更鸟》中称为 warbler) - “基本复制器”。

你所说的“dup”实际上是“starling-prime”组合器。

Haskell 有一个相当小的“组合器基础”(参见 Data.Function),加上一些 Applicative 和 Monadic 操作,凭借 Applicative 和 Monad 的函数实例添加了更多“标准”组合器(Applicative 中的 <*> 是 S - starling 组合器对于功能实例, liftA2 和 liftM2 是 starling-prime)。社区中似乎对扩展 Data.Function 没有太多热情,因此虽然组合器很有趣,但实际上,在组合器无法直接可用的情况下,我更喜欢长期使用。

What you call 'doubleArgs' is more often called dup - it is the W combinator (called warbler in To Mock a Mockingbird) - "the elementary duplicator".

What you call 'dup' is actually the 'starling-prime' combinator.

Haskell has a fairly small "combinator basis" see Data.Function, plus some Applicative and Monadic operations add more "standard" combinators by virtue of the function instances for Applicative and Monad (<*> from Applicative is the S - starling combinator for the functional instance, liftA2 & liftM2 are starling-prime). There doesn't seem to be much enthusiasm in the community for expanding Data.Function, so whilst combinators are good fun, pragmatically I've come to prefer long-hand in situations where a combinator is not directly available.

摇划花蜜的午后 2024-10-12 09:38:08

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

import Control.Arrow

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

&&&(“fanout”)将参数分配给两个函数并返回结果对。 >>>(“然后”)反转函数应用顺序,从而允许从左到右形成一系列操作。 second 仅适用于一对的第二部分。当然,您需要在末尾添加一个 uncurry 来将这对输入到需要两个参数的函数中。

Here is another solution for the second part of my question: Arrows!

import Control.Arrow

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

The &&& ("fanout") distributes an argument to two functions and returns the pair of the results. >>> ("and then") reverses the function application order, which allows to have a chain of operations from left to right. second works only on the second part of a pair. Of course you need an uncurry at the end to feed the pair in a function expecting two arguments.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文