简体   繁体   中英

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.

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) . 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) . While this is very close to LiftA2 you may extend this pattern indefinitely. 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. 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;

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. 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:

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.

here an application of the bind function that I used for solving the 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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