Haskell 两个二元函数的函数组合?

Haskell Function composition of two binary functions?

我正在努力完成 20 Intermediate Haskell exercises,但在练习 13 上卡住了:

-- Exercise 13
-- Relative Difficulty: 6
apple :: (Misty m) => m a -> m (a -> b) -> m b
apple = error "todo"

其中 Misty Typeclass 本质上是 Monad Typeclass 并且是这样实现的:

class Misty m where
    banana :: (a -> m b) -> m a -> m b
    unicorn :: a -> m a

出于好奇,我在网上找到了这个练习的解决方案

apple = banana . flip furry'

其中 furry' 是实现为

的 liftM 版本
furry' f mi = banana (\x -> unicorn (f x)) mi

我不明白的是函数组合 (.) 在两个二元函数(即 banana 和 flipped furry')上的使用,如果有人可以完成这个评估,我认为这会对我有所帮助很多。

让我们一步步开始吧。 Misty 类型类已给出:

class Misty m where 
  banana :: (a -> m b) -> m a -> m b 
  unicorn :: a -> m a

此外 furry' 已经在这些练习中的较早问题中得到解决:

furry' :: Misty m => (a -> b) -> m a -> m b
furry' f mi = banana (\x -> unicorn (f x)) mi

现在您有 apple 函数,您必须定义它:

apple :: (Misty m) => m a -> m (a -> b) -> m b
apple = error "todo"

现在尝试遵循类型签名。假设您这样定义 apple

apple xs ys

xs will have type of m a

ys will have type of m (a -> b)

现在你能看出上述类型与furry'之间的关系了吗?所以 你必须以某种方式将 xsys 应用到 furry' 现在因为它是 第二个参数是m a,你已经在xs中有了,你可以使用 flip获取方式:

flip furry' :: m a -> (a -> b) -> m b

所以你可以将 xs 应用到它的第一个参数,你将拥有 以下类型签名:

(flip furry') xs :: (a -> b) -> m b -------- 方程 1

猜猜如何应用它 ys?尽量统一上面的类型 第一个参数为 banana 的签名:

那会给你:

a ~ (a -> b)
m b ~ (m b)

因此,banana 的类型签名从

转换而来
banana :: (a -> m b) -> m a -> m b

banana :: ((a -> b) -> m b) -> m (a -> b) -> m b 

现在从 Equation (1) 我们知道 (flip furry') xs 类型签名匹配 bananays 的第一个参数匹配第二个参数 banana。这给了你 apple:

的定义
apple :: (Misty m) => m a -> m (a -> b) -> m b
apple xs ys = banana ((flip furry') xs ) ys

可以用pointfree的方式表示为:

apple :: (Misty m) => m a -> m (a -> b) -> m b
apple = banana . flip furry'