Haskell中的隐式函数组合

13

假设我有一个像这样定义的mean函数:

mean xs = sum xs / (fromIntegral $ length xs)

但我希望以某种隐含的形式呈现,就像这样:

mean = sum / (fromIntegral . length)

是否有内置的Haskell方法可以做类似于这样的事情,而无需构建自己的 tacit 函数(类似于这样):

有没有内置的Haskell方法可以实现这种功能,而不需要构建自己的“tacit”函数(类似于下面的示例):

tacit :: (a -> b -> c) -> (d -> a) -> (d -> b) -> d -> c
tacit a b c i = a (b i) (c i)

在这个表单里,该函数看起来是这样的:

mean = tacit (/) sum (fromIntegral . length)

但是感觉可能有一种避免使用这样显式函数的方法。我只是想知道:Haskell中是否有一些内置的方法可以实现这个功能呢?


2
请查看以下网址:http://squing.blogspot.com/2008/11/beautiful-folding.html,http://conal.net/blog/posts/more-beautiful-fold-zipping - sdcvvc
1
你所说的“tacit”的技术术语是“point free”(有时人们会用“pointless”来讽刺)。术语“point”来自拓扑学,实际上指的是变量。 - Paul Johnson
@PaulJohnson,“tacit”是J编程语言(和其他一些语言?)用来指称更常见的“point free”的术语。 - Alex R
2个回答

20

应用函子在这里表现得非常好。

import Control.Applicative

mean = (/) <$> sum <*> (fromIntegral . length)

14

是的,你的 tacit 函数在 (->) r monad 中等同于 liftM2liftM2Control.Monad 中,而 Monad 的函数实例在 Control.Monad.Instances 中)。

我使用 pointfree 程序找到了这个结果(你可以通过 cabal install pointfree 安装它),调用方式为:

$ pointfree '\xs -> sum xs / (fromIntegral $ length xs)'

(在Unix终端中)


8
然后你可以为(->) r创建一个 Num 实例,这样 mean = sum / (fromIntegral . length) 就能够正常工作了。 - Sjoerd Visscher
5
@SjoerdVisscher说需要添加Fractional,因为要用到(/)。我尝试了一下并确认这就是所需的全部内容。 - Luis Casillas
4
有趣的补充是,一旦你有了Num r => Num (a -> r)实例,你可以将加法应用于它本身:(+) + (+)成为一个合法的表达式(等效于\x y -> (x + y) + (x + y))。 - Luis Casillas
3
啊,没错。而且,“1 2 3 4”也是合法的表达式。很明显这不是一个内置实例。 - Sjoerd Visscher
2
哎呀,我没想到那个。但更糟糕的是,如果你的一个模块导入了任何直接或间接使用此实例的模块,你将得到这个实例。所以,你真的应该用 newtype 来包装它——在这种情况下,额外的语法开销意味着你可能还不如使用 Applicative - Luis Casillas
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接