应用函子的目的是什么?

Tri*_*Gao 4 haskell functional-programming

当具有以下签名的函数有用时,任何人都可以分享良好的现实生活情况吗?

f (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

我无法真正看到我需要的东西,比如来自Learn-you-a-haskell的教科书示例 [(+),(*)] <*> [1,2] <*> [3,4]

lef*_*out 7

Applicative可以用于许多你可能也用monad做的东西,但是它们并不真正需要那个类的强大功能.(更准确地说,只要仿函数的"形状"不依赖于其中的值,那么Applicative就足够了.)例如,像

foobar :: IO [String]
foobar = do
   fooTxt <- readFile "foo.txt"
   barTxt <- readFile "bar.txt"
   return $ zip (lines fooTxt) (lines barTxt)
Run Code Online (Sandbox Code Playgroud)

也可以写

foobar = zip <$> (lines <$> readFile "foo.txt")
             <*> (lines <$> readFile "bar.txt")
Run Code Online (Sandbox Code Playgroud)

在这种情况下,这只会使它变得更短,但在其他情况下,它也可以提高性能(因为Applicative不太通用,可以进行更多优化)或允许您使代码比使用Monad接口时更通用.


The*_*ive 6

我最常用的是为函数使用多个Monadic(或在本例中为Applicative)值.我使用它的一种非常常见的方式是构造函数.

考虑:

randomAge :: Rand StdGen Int
randomHeight :: Rand StdGen Double
randomWeight :: Rand StdGen Double

data Person = Person { age :: Int, height :: Double, weight :: Double }

randomPerson :: Rand StdGen Person
randomPerson = Person <$> randomAge <*> randomHeight <*> randomWeight

-- If we only had Monads...
randomPerson' :: Rand StdGen Person
randomPerson' = liftM3 Person randomAge randomHeight randomWeight
-- or worse...
randomPerson'' = randomAge >>= \ra -> randomHeight >>= \rh -> randomWeight >>= \rw -> return $ Person ra rh rw
Run Code Online (Sandbox Code Playgroud)

或者这个来自FPComplete的JSON解析器Aeson教程的例子:

instance FromJSON Person where
 parseJSON (Object v) =
    Person <$> v .: "firstName"
           <*> v .: "lastName"
           <*> v .: "age"
           <*> v .: "likesPizza"
 parseJSON _ = mzero
Run Code Online (Sandbox Code Playgroud)

或者来自Parser CombinatorsReal World Haskell章节中的这个例子:

ghci> let parser = (++) <$> string "HT" <*> (string "TP" <|> string "ML")
Run Code Online (Sandbox Code Playgroud)

在大多数情况下Applicatives当你是有用的f :: a -> b -> c,你必须m am b你想要的m c.

编辑:那说还有其他用途.例如,Applicative可以用作修改可遍历数据结构的非常好的方法.例如,通过具有函数树将树应用于值,从而将值转换为树.或者在没有列表理解语法的情况下进行非确定性列表操作.

它可能有一些意想不到的应用.例如,使用->Monad:

> (<*>) (+) (+1) 2
5
Run Code Online (Sandbox Code Playgroud)

最后一个有点深奥,不太可能在实际环境中使用,但它表明你可以在很多方面使用Applicatives.