2017-10-08 64 views
13

Haskell有在标准库函数定义FunctorApplicativeMonad实例(具体地,部分应用类型(->) a),围绕功能组成内置仿/应用性/单子实例。用例用于功能

理解这些实例是一个很好的弯曲练习,但我的问题在于这些实例的实际用途。我很乐意听到人们使用这些实际代码的现实场景。

+7

的[读卡器单子](http://hackage.haskell.org/package/mtl/docs/Control-Monad-Reader.html)基本上是一个NEWTYPE包装纸围绕'( - >)'。 – melpomene

+0

我一直都在使用它们。可能你自己不知道:'.'只是'fmap'。 – Bergi

+0

@Bergi:当然,我想这个问题是为什么,而不是使用它们只是利用 –

回答

3

有时您想将a -> m b(其中mApplicative)的函数作为Applicative自己处理。编写验证器或解析器时经常发生这种情况。要做到这一点

一种方法是使用Data.Functor.Compose,它寄生在的(->) amApplicative实例给出Applicative实例组成:

import Control.Applicative 
import Data.Functor.Compose 

type Star m a b = Compose ((->) a) m b 

readPrompt :: Star IO String Int 
readPrompt = Compose $ \prompt -> do 
    putStrLn $ prompt ++ ":" 
    readLn 

main :: IO() 
main = do 
    r <- getCompose (liftA2 (,) readPrompt readPrompt) "write number" 
    print r 

还有其他的方法,比如创建自己的NEWTYPE ,或者使用ready-madenewtypes,从基地或其他库。

7

涉及Functor和Applicative功能实例的常见模式是例如(+) <$> (*2) <*> (subtract 1)。当您必须使用单个值输入一系列函数时,这非常有用。在这种情况下,上述相当于\x -> (x * 2) + (x - 1)。虽然这非常接近LiftA2,但您可以无限期地扩展此模式。如果你有一个f函数来接受像a -> a -> a -> a -> a -> b这样的5个参数,你可以像f <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2)那样做,并用一个值给它提供。就像在下面的情况一样;

Prelude> (,,,,) <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) $ 10 
(12.0,20.0,11.0,7.0,5.0) 

编辑:信用为@Will内斯的矿井下的另一个话题评论再评论,来了应用性的功能上一个美丽的使用;

Prelude> let isAscending = and . (zipWith (<=) <*> drop 1) 
Prelude> isAscending [1,2,3,4] 
True 
Prelude> isAscending [1,2,5,4] 
False 
+0

感谢您的意见。所以你发布的5元组例子。它可以改写为((x - >(x + 2,x * 2,x + 1,x-3,x/2))10' - 这里的应用的优点是不需要重复'x'? –

+0

@Eli Bendersky的主要区别是,在应用形式,如果你知道的主要功能有多少参数需要,整个事情是功能分解(即可以动态撰写的参数,你喜欢的方式)在lambda形式,你必须同时手边有一个可靠的lambda函数。 – Redu

+0

你是说我们已经有了一个函数,比如'(,,,,)''而不必手工编写lambda? –