Haskell为标准库中的函数(特别是部分应用的类型Functor
)定义了Applicative
,Monad
和(->) a
个实例,围绕函数组合构建。
理解这些实例是一个很好的心灵弯曲练习,但我的问题是关于这些实例的实际用法。我很高兴听到人们使用这些实际代码的现实场景。
答案 0 :(得分: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 Ness在另一个主题下对我的评论进行重新评论的信用,这里有一个关于功能的应用的美妙用法;
Prelude> let isAscending = and . (zipWith (<=) <*> drop 1)
Prelude> isAscending [1,2,3,4]
True
Prelude> isAscending [1,2,5,4]
False
答案 1 :(得分:4)
有时您希望将a -> m b
形式的函数(m
为Applicative
)视为Applicative
自身。编写验证器或解析器时经常会发生这种情况。
执行此操作的一种方法是使用Data.Functor.Compose
,Applicative
实例(->) a
和m
为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
实例组合物:
@include('banners.bottom')
还有其他方法,例如创建自己的新类型,或使用 base 或其他库中的ready-made newtypes。
答案 2 :(得分:0)
这里是我用来解决Diamond Kata的bind函数的一个应用程序。采取一个简单的函数来镜像其输入,丢弃最后一个元素
mirror :: [a] -> [a]
mirror xs = xs ++ (reverse . init) xs
让我们重写一下
mirror xs = (++) xs ((reverse . init) xs)
mirror xs = flip (++) ((reverse . init) xs) xs
mirror xs = (reverse . init >>= flip (++)) xs
mirror = reverse . init >>= flip (++)
这是我完整实施此卡塔的方法:https://github.com/enolive/exercism/blob/master/haskell/diamond/src/Diamond.hs