我怎样才能用这种类型签名制作一个组合器?
How can I make a combinator with this type signature?
我一直在尝试用这种类型签名制作一个组合器:
(a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
我浏览了 Data.Aviary.Birds 和所有我能找到的默认编程帮助站点,但无济于事。另外,如果有一个通用的算法来制作这些,将不胜感激,但不是必需的。
我们的定义会这样开始:
foo :: (a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
foo abc cde a b d = e
现在让我们填补缺失的部分。
我们需要一个e
;获得它的唯一方法是将第二个函数应用于 c
和 d
.
e = cde c d
我们已经得到一个 d
,但我们需要一个 c
。我们如何获得 c
?通过将第一个函数应用于 a
和 b
.
c = abc a b
我们都得到了这两个,所以我们完成了。
foo :: (a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
foo abc cde a b d = e
where
e = cde c d
c = abc a b
我们可能会到此为止。这是一个非常好的定义。
但是如果我们想让它更简洁,让我们从替换 e
的定义开始
foo abc cde a b d = cde c d
where
c = abc a b
然后是c
foo abc cde a b d = cde (abc a b) d
我们立即看到我们可以 eta reduce 删除 d
。
foo abc cde a b = cde (abc a b)
该类型现在稍微更通用。 d -> e
已合并为一个类型变量,因为它实际上可以是任何类型。
foo :: (a -> b -> c) -> (c -> de) -> a -> b -> de
我们现在可以在鸟舍中看到我们的组合器实际上是翻转的黑鸟。
blackbird :: (c -> d) -> (a -> b -> c) -> a -> b -> d
foo :: (a -> b -> c) -> (c -> de) -> a -> b -> de
foo = flip blackbird
确实,如果我们查看 blackbird 的源代码,它看起来很像我们写的。
-- | B1 combinator - blackbird - specs 'oo'.
blackbird :: (c -> d) -> (a -> b -> c) -> a -> b -> d
blackbird f g x y = f (g x y)
我们可以更进一步吗point-free?我们可能会考虑取消柯里化abc
foo abc cde a b = cde (uncurry abc (a, b))
用函数组合重写这个嵌套
foo abc cde a b = (cde . uncurry abc) (a, b)
又回来了
foo abc cde a b = curry (cde . uncurry abc) a b
现在我们可以再砍掉两个参数。
foo abc cde = curry (cde . uncurry abc)
我们绝对应该到此为止。但是如果我们现在翻转参数会怎样
foo = flip $ \cde abc -> curry (cde . uncurry abc)
重写右半部分使其成为point-free
foo = flip $ \cde abc -> (curry . ((cde .) . uncurry)) abc
eta 再次减少
foo = flip $ \cde -> curry . ((cde .) . uncurry)
然后迈出最后可笑的一步
foo = flip $ (curry .) . (. uncurry) . (.)
我们现在point-free!
有一个非常简单的方法:作弊。让我们从找出我们想要的功能开始。为此,我们转到 Djinn。输入
f :: (a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
然后返回
f a b c d = b (a c d)
不错。现在前往 pointfree.io。粘贴来自 Djinn 的定义,它显示
f = flip ((.) . (.))
完成。
我一直在尝试用这种类型签名制作一个组合器:
(a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
我浏览了 Data.Aviary.Birds 和所有我能找到的默认编程帮助站点,但无济于事。另外,如果有一个通用的算法来制作这些,将不胜感激,但不是必需的。
我们的定义会这样开始:
foo :: (a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
foo abc cde a b d = e
现在让我们填补缺失的部分。
我们需要一个e
;获得它的唯一方法是将第二个函数应用于 c
和 d
.
e = cde c d
我们已经得到一个 d
,但我们需要一个 c
。我们如何获得 c
?通过将第一个函数应用于 a
和 b
.
c = abc a b
我们都得到了这两个,所以我们完成了。
foo :: (a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
foo abc cde a b d = e
where
e = cde c d
c = abc a b
我们可能会到此为止。这是一个非常好的定义。
但是如果我们想让它更简洁,让我们从替换 e
foo abc cde a b d = cde c d
where
c = abc a b
然后是c
foo abc cde a b d = cde (abc a b) d
我们立即看到我们可以 eta reduce 删除 d
。
foo abc cde a b = cde (abc a b)
该类型现在稍微更通用。 d -> e
已合并为一个类型变量,因为它实际上可以是任何类型。
foo :: (a -> b -> c) -> (c -> de) -> a -> b -> de
我们现在可以在鸟舍中看到我们的组合器实际上是翻转的黑鸟。
blackbird :: (c -> d) -> (a -> b -> c) -> a -> b -> d
foo :: (a -> b -> c) -> (c -> de) -> a -> b -> de
foo = flip blackbird
确实,如果我们查看 blackbird 的源代码,它看起来很像我们写的。
-- | B1 combinator - blackbird - specs 'oo'.
blackbird :: (c -> d) -> (a -> b -> c) -> a -> b -> d
blackbird f g x y = f (g x y)
我们可以更进一步吗point-free?我们可能会考虑取消柯里化abc
foo abc cde a b = cde (uncurry abc (a, b))
用函数组合重写这个嵌套
foo abc cde a b = (cde . uncurry abc) (a, b)
又回来了
foo abc cde a b = curry (cde . uncurry abc) a b
现在我们可以再砍掉两个参数。
foo abc cde = curry (cde . uncurry abc)
我们绝对应该到此为止。但是如果我们现在翻转参数会怎样
foo = flip $ \cde abc -> curry (cde . uncurry abc)
重写右半部分使其成为point-free
foo = flip $ \cde abc -> (curry . ((cde .) . uncurry)) abc
eta 再次减少
foo = flip $ \cde -> curry . ((cde .) . uncurry)
然后迈出最后可笑的一步
foo = flip $ (curry .) . (. uncurry) . (.)
我们现在point-free!
有一个非常简单的方法:作弊。让我们从找出我们想要的功能开始。为此,我们转到 Djinn。输入
f :: (a -> b -> c) -> (c -> d -> e) -> a -> b -> d -> e
然后返回
f a b c d = b (a c d)
不错。现在前往 pointfree.io。粘贴来自 Djinn 的定义,它显示
f = flip ((.) . (.))
完成。