Haskell函数组成 - (a - > b) - >(a - > c) - >(b - > c - > d) - >(a - > d)

MIJ*_*THY 7 lambda haskell pointfree function-composition

我想了解如何以无点方式完成以下工作:

withinBounds :: [Int] -> Bool
withinBounds xs = (all (>= 0) xs) && (all (<= 8) xs)
Run Code Online (Sandbox Code Playgroud)

我明白,出于可读性/理智的考虑,以这种方式编写它是优越的,但我想更多地了解如何编写函数.我一直在摸索着如何做到这一点.整个(扩展?)类型签名是

[Int] -> ([Int] -> Bool) -> ([Int] -> Bool) -> (Bool -> Bool -> Bool) -> Bool
Run Code Online (Sandbox Code Playgroud)

我想要的组合的类型签名是

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

我用以混蛋 - lambda形式的笔记写下了以下内容.如果有一种方法可以在某种程度上简化lambda演算的问题,那么如果可以解释它也会很棒:

\L@[] ->  \f1@([] -> Bool) -> \f2@([] -> Bool) -> \f3@(Bool -> Bool -> Bool) -> f3.(f1.L).(f2.L) 
Run Code Online (Sandbox Code Playgroud)

在上面,.是应用程序,@正在捕获(所以f3是(Bool - > Bool - > Bool)的另一个名称).非常感谢.

编辑:我知道这是不是最优化的或可重用的代码,我知道把这个变成自由点,使得它在可读性等的澄清方面糟糕的是,我问我怎么可以把它变成自由点,因为我想了解有关哈斯克尔和作曲的更多信息.

Edit2:关于无点的非常好的答案

Saf*_*eli 9

你可以使用函数是Applicative的事实.并写withinBounds这样:

withinBounds = pure (&&) <*> all (>= 0) <*> all (<= 8)
Run Code Online (Sandbox Code Playgroud)

或者这样:

withinBounds = (&&) <$> all (>= 0) <*> all (<= 8)
Run Code Online (Sandbox Code Playgroud)

你可以在这里这里阅读有关Applicatives的内容


lef*_*out 9

有一个类基本上专门用于无点组合有多个"通道":Arrow.如果你决心让所有东西都没有点,那么这就是IMO的最佳选择.关于这一点的丑陋是你经常需要uncurry函数:

import Control.Arrow

withinBounds = all (>=0) &&& all (<=8) >>> uncurry (&&)
Run Code Online (Sandbox Code Playgroud)

如何使用图表最好地理解其工作原理:

      all (>=0) ????
       ?                ?
???? &&&            >>>  uncurry (&&) ???
       ?                ?
      all (<=8) ???? 
Run Code Online (Sandbox Code Playgroud)

Arrow在广义环境中工作; 不仅适用于Hask功能,还适用于任何合适的类别.但它足以将其应用于函数.


Dan*_*ner 2

围绕整个问题进行最终运行,我想我可能会这样写:

import Data.Ix
withinBounds = all (inRange (0, 8))
Run Code Online (Sandbox Code Playgroud)

当然,这有点冒险,因为那时人们自然会问如何inRange以无点的方式实现。如果你绝对不能使用inRange,那么我会这样内联实现它:

withinBounds = all (liftA2 (&&) (>=0) (<=8))
Run Code Online (Sandbox Code Playgroud)

这使用读者应用程序向两个函数提供单个参数。liftA2是您请求的组合函数,尽管参数已翻转:

requested :: (a -> b) -> (a -> c) -> (b -> c -> d) -> (a -> d)
liftA2    :: (b -> c -> d) -> (a -> b) -> (a -> c) -> (a -> d)
Run Code Online (Sandbox Code Playgroud)