简体   繁体   English

函数的functor / applicative / monad实例的用例

[英]Use cases for functor/applicative/monad instances for functions

Haskell has Functor , Applicative and Monad instances defined for functions (specifically the partially applied type (->) a ) in the standard library, built around function composition. Haskell具有为函数定义的FunctorApplicativeMonad实例(特别是部分应用的类型(->) a )在标准库中,围绕函数组合构建。

Understanding these instances is a nice mind-bender exercise, but my question here is about the practical uses of these instances. 理解这些实例是一个很好的心灵弯曲练习,但我的问题是关于这些实例的实际用法。 I'd be happy to hear about realistic scenarios where folks used these for some practical code. 我很高兴听到人们使用这些实际代码的现实场景。

A common pattern that involves Functor and Applicative instances of functions is for example (+) <$> (*2) <*> (subtract 1) . 涉及Functor和Applicative函数实例的常见模式是例如(+) <$> (*2) <*> (subtract 1) This is particularly useful when you have to feed a series of function with a single value. 当您必须使用单个值提供一系列函数时,这尤其有用。 In this case the above is equivalent to \\x -> (x * 2) + (x - 1) . 在这种情况下,上述等价于\\x -> (x * 2) + (x - 1) While this is very close to LiftA2 you may extend this pattern indefinitely. 虽然这与LiftA2非常接近, LiftA2您可以无限延长此模式。 If you have an f function to take 5 parameters like a -> a -> a -> a -> a -> b you may do like f <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) and feed it with a single value. 如果你有一个f函数来取5个参数,比如a -> a -> a -> a -> a -> b你可能会喜欢f <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2)并用单个值输入。 Just like in below case ; 就像下面的情况一样;

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

Edit: Credit for a re-comment of @Will Ness for a comment of mine under another topic, here comes a beautiful usage of applicative over functions; 编辑:感谢@Will Ness重新评论我的另一个主题的评论,这里有一个关于功能的应用的美丽用法;

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

Sometimes you want to treat functions of the form a -> mb (where m is an Applicative ) as Applicative s themselves. 有时您希望将形式a -> mb函数a -> mb (其中mApplicative )视为Applicative s本身。 This often happens when writing validators, or parsers. 编写验证器或解析器时经常会发生这种情况。

One way to do this is to use Data.Functor.Compose , which piggybacks on the Applicative instances of (->) a and m to give an Applicative instance for the composition: 这样做的一种方式是使用Data.Functor.Compose ,其寄生在所述Applicative的实例(->) am ,得到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

There are other ways, like creating your own newtype, or using ready-made newtypes from base or other libraries. 还有其他方法,比如创建自己的newtype,或者使用基础库或其他库中的现成 newtypes

here an application of the bind function that I used for solving the Diamond Kata. 这里是我用来解决Diamond Kata的绑定函数的应用。 Take a simple function that mirrors its input discarding the last element 采用一个简单的函数来反映其输入,丢弃最后一个元素

mirror :: [a] -> [a]
mirror xs = xs ++ (reverse . init) xs

let's rewrite it a bit 让我们重写一下

mirror xs = (++) xs ((reverse . init) xs)
mirror xs = flip (++) ((reverse . init) xs) xs
mirror xs = (reverse . init >>= flip (++)) xs
mirror = reverse . init >>= flip (++)

Here is my complete implementation of this Kata: https://github.com/enolive/exercism/blob/master/haskell/diamond/src/Diamond.hs 以下是我对此Kata的完整实现: https//github.com/enolive/exercism/blob/master/haskell/diamond/src/Diamond.hs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM