在Haskell中hi ::(b - > c) - >(a - > b) - >(a - > c)

jcm*_*jcm 6 haskell functional-programming

我在Haskell中有以下类型签名:

hi :: (b -> c) -> (a -> b) -> (a -> c)
Run Code Online (Sandbox Code Playgroud)

我想写一个具体的实现,但我真的很难理解从哪里开始.我知道hi需要一个函数(b - > c),它返回一个函数(a - > b),它最终返回一个函数(a - > c).

谁能告诉我一个具体实现的例子?我怎么知道从哪里开始这样的事情以及定义左侧的内容?

Chr*_*lor 26

想到这一点的一种方法是作为一个函数,它接受a (b -> c)和a (a -> b)并返回另一个函数(a -> c).那么让我们从那开始吧

hi f g = undefined       -- f :: b -> c, g :: a -> b
Run Code Online (Sandbox Code Playgroud)

我们知道返回类型必须是一个函数(a -> c)-

hi f g = \a -> undefined -- f :: b -> c, g :: a -> b
Run Code Online (Sandbox Code Playgroud)

我们现在有型的东西a在右手边,我们有一个功能,g :: a -> b所以明智的做法(实际上,我们所能做的唯一的事情)是适用ga

hi f g = \a -> g a       -- ok, this fails to typecheck...
Run Code Online (Sandbox Code Playgroud)

表达式g a有类型b,而且f :: b -> c,我们希望最终得到一个c.再说一遍,我们只能做一件事 -

hi f g = \a -> f (g a)
Run Code Online (Sandbox Code Playgroud)

这种类型检查!我们现在开始清理过程.我们可以移动a到等号的左边

hi f g a = f (g a)
Run Code Online (Sandbox Code Playgroud)

而且,如果您碰巧知道合成运算符,.您可能会注意到它可以在这里使用

hi f g a = (f . g) a
Run Code Online (Sandbox Code Playgroud)

现在a双方都是多余的(这称为eta减少)

hi f g = f . g
Run Code Online (Sandbox Code Playgroud)

我们可以.使用函数形式将运算符拉到表达式的前面(.)

hi f g = (.) f g
Run Code Online (Sandbox Code Playgroud)

现在gf它们都是多余的(eta减少的另外两个应用)

hi = (.)
Run Code Online (Sandbox Code Playgroud)

所以你的功能hi只不过是功能组合.

  • @cookiemonster因为两个定义`fa = e`和`f =\a - > e`对于任何表达式'e`意味着相同的事情.这种转变(当他们知道他们是平等的时候用另一件事取而代之)被称为[等于推理](http://www.haskellforall.com/2013/12/equational-reasoning.html)并且是一种非常强大的方法编写代码. (2认同)

Nic*_*las 5

您读错了:该->运算符是右结合的。因此,您的签名是:(b->c) -> ((a->b) -> (a->c))。因此,您可以将其理解为:给定一个函数 from bto c,它返回一个函数,该函数接受一个函数 from ato bto 最后返回一个函数 from ato c

从那里,您应该能够自己解决这个练习。