Chr*_*lor 8 haskell combinators pointfree higher-order-functions
我正在完成20个中级Haskell练习,这是一个非常有趣的练习.它涉及到执行类型类的各种实例Functor和Monad(而这需要职能FunctorS和MonadS作为参数),但像可爱的名字Furry和Misty掩饰我们正在做什么(一些有趣的代码使).
我一直试图以无点的方式做一些这样的事情,我想知道是否有一个将点 - 完全(?)定义转变为无点定义的一般方案.例如,以下是类型类Misty:
class Misty m where
unicorn :: a -> m a
banana :: (a -> m b) -> m a -> m b
Run Code Online (Sandbox Code Playgroud)
(函数unicorn和banana是,return并且>>=,如果不是很明显),这是我的apple(相当于flip ap)的实现:
apple :: (Misty m) => m a -> m (a -> b) -> m b
apple x f = banana (\g -> banana (unicorn . g) x) f
Run Code Online (Sandbox Code Playgroud)
演习后面的部分有你实现的版本liftM,liftM2等等.这里是我的解决方案:
appleTurnover :: (Misty m) => m (a -> b) -> m a -> m b
appleTurnover = flip apple
banana1 :: (Misty m) => (a -> b) -> m a -> m b
banana1 = appleTurnover . unicorn
banana2 :: (Misty m) => (a -> b -> c) -> m a -> m b -> m c
banana2 f = appleTurnover . banana1 f
banana3 :: (Misty m) => (a -> b -> c -> d) -> m a -> m b -> m c -> m d
banana3 f x = appleTurnover . banana2 f x
banana4 :: (Misty m) => (a -> b -> c -> d -> e) -> m a -> m b -> m c -> m d -> m e
banana4 f x y = appleTurnover . banana3 f x y
Run Code Online (Sandbox Code Playgroud)
现在,banana1(相当于liftM或fmap)我能够通过合适的定义以无点样式实现appleTurnover.但是使用其他三个函数我必须使用参数.
我的问题是:是否有将这些定义转化为无点定义的方法?
C. *_*ann 11
如该pointfree实用程序所示,可以自动执行任何此类转换.但是,结果经常被混淆而不是改进.如果一个人的目标是提高可读性而不是破坏它,那么第一个目标应该是找出为什么一个表达式有一个特殊的结构,找到一个合适的抽象,并建立东西的方式.
最简单的结构就是在线性管道中将事物链接在一起,这是简单的功能组合.这让我们自己走得很远,但是你注意到它并没有处理所有事情.
一个概括是具有附加参数的函数,这些参数可以递增地构建.这是一个例子:定义onResult = (. (.)).现在,onResult对初始值应用n次id给出了具有n元函数结果的函数组合.因此我们可以定义comp2 = onResult (.),然后编写comp2 not (&&)以定义NAND操作.
另一个概括 - 实际上包含上述内容 - 是定义将函数应用于更大值的组件的运算符.这里有一个例子是first和second中Control.Arrow,其中2元组工作.Conal Elliott的语义编辑器组合器基于这种方法.
稍有不同的情况是当你在某种类型b和函数上有一个多参数函数时a -> b,需要将它们组合成一个多参数函数a.对于2-ary函数的常见情况,该模块Data.Function提供了on组合器,您可以使用它来编写表达式,比如compare `on` fst在它们的第一个元素上比较2元组.
当一个参数被多次使用时,这是一个棘手的问题,但这里也有一些有意义的重复模式也可以被提取出来.这里的一个常见情况是将多个函数应用于单个参数,然后使用另一个函数收集结果.这恰好对应Applicative于函数的实例,这使我们可以编写表达式(&&) <$> (> 3) <*> (< 9)来检查数字是否落在给定范围内.
重要的是,如果你想在实际代码中使用任何一个,那就要考虑表达式的含义以及它在结构中的反映方式.如果你这样做,然后使用有意义的组合器将它重构为无点样式,你通常会使代码的意图比原本更清晰,不像典型的输出pointfree.
是! 其中一个技巧是用前缀表示法而不是中缀表示你的点.然后你应该能够找到看起来像功能组合的新东西.这是一个例子:
banana2 f = appleTurnover . banana1 f
= (.) appleTurnover (banana1 f)
= ((.) appleTurnOver) . banana1 $ f
banana2 = (appleTurnover .) . banana1
Run Code Online (Sandbox Code Playgroud)
pointfree实用程序的源代码包含更多内容,但是这个代码处理了很多情况.
banana4 f x y = appleTurnover . banana3 f x y
= (.) appleTurnover ((banana3 f x) y)
= ((.) appleTurnover) . (banana3 f x) $ y
banana4 f x = ((.) appleTurnover) . (banana3 f x)
= (.) ((.) appleTurnover) (banana3 f x)
= ((.) ((.) appleTurnover)) ((banana3 f) x)
= ((.) ((.) appleTurnover)) . (banana3 f) $ x
banana4 f = ((.) ((.) appleTurnover)) . (banana3 f)
= (.) ((.) ((.) appleTurnover)) (banana3 f)
= ((.) ((.) ((.) appleTurnover))) (banana3 f)
= ((.) ((.) ((.) appleTurnover))) . banana3 $ f
banana4 = ((.) ((.) ((.) appleTurnover))) . banana3
= (((appleTurnover .) .) .) . banana3
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
599 次 |
| 最近记录: |