module Main where foo = undefined -- main :: IO () main = do putStrLn "Input a: " a <- getLine -- 1 putStrLn "Input b: " b <- getLine -- 2 print (foo ab) --
pure1arg :: Int -> Int pure1arg = (+ 1) -- , 1 pure2args :: Int -> Int -> Int pure2args = (+) -- , 2 unsafe2args :: Int -> Int -> Int unsafe2args = div -- , 2 foo :: String -> String -> Int foo ab = unsafe2args extraUnsafeE unsafeC -- , where unsafeA :: Int unsafeA = read a -- unsafeB :: Int unsafeB = read b -- unsafeA unsafeC :: Int unsafeC = pure1arg unsafeB -- 1 reallyUnsafeD :: Int reallyUnsafeD = pure2args unsafeA unsafeC -- 2 extraUnsafeE :: Int extraUnsafeE = unsafe2args unsafeA reallyUnsafeD -- 2 . 2 .
foo
is essentially [no matter what] a mixture of integer division and sums.0
, and the user can enter not the numbers, but the left strings, and when converting strings to numbers can throw out an error. Our code is not safe. module Main where import Control.Exception (IOException, catch) printError :: IOException -> IO () printError = print pure2args :: Int -> Int -> Int pure2args = (+) pure1arg :: Int -> Int pure1arg = (+ 1) unsafe2args :: Int -> Int -> Int unsafe2args ab = if b == 0 then error "Error 'unsafe2args' : wrong 2nd argument = 0" --unsafe source of IOException else div ab foo :: String -> String -> Int foo ab = unsafe2args extraUnsafeE unsafeC where unsafeA :: Int unsafeA = read a --unsafe source of IOException unsafeB :: Int unsafeB = read b --unsafe source of IOException unsafeC :: Int unsafeC = pure1arg unsafeB reallyUnsafeD :: Int reallyUnsafeD = pure2args unsafeA unsafeC extraUnsafeE :: Int extraUnsafeE = unsafe2args unsafeA reallyUnsafeD main :: IO () main = do putStrLn "Input a: " a <- getLine putStrLn "Input b: " b <- getLine catch (print (foo ab)) printError -- IOException
Option
, in Haskell, it is called Maybe a
. import Prelude hiding (Maybe) -- . data Maybe a = Nothing | Just a deriving Show
deriving
part, we simply say that we ask the compiler to be able to translate our data type into a string. show Nothing == "Nothing" show (Just 3) == "Just 3"
Nothing
if we have no data, and Just a
if it has one. maybeResult2args :: Int -> Int -> Maybe Int maybeResult2args ab = if b == 0 then Nothing --safe else Just (div ab) ... maybeA :: Maybe Int maybeA = readMaybe a --safe maybeB :: Maybe Int maybeB = readMaybe b --safe
Nothing
, if everything is in order, then Just
. pure2args :: Int -> Int -> Int pure2args = (+) safePure2args :: Maybe Int -> Maybe Int -> Maybe Int safePure2args ab = case a of Nothing -> Nothing Just a' -> case b of Nothing -> Nothing Just b' -> Just (pure2args a' b') pure1arg :: Int -> Int pure1arg = (+ 1) safePure1arg :: Maybe Int -> Maybe Int safePure1arg a = case a of Nothing -> Nothing Just a' -> Just (pure1arg a') maybeResult2args :: Int -> Int -> Maybe Int maybeResult2args ab = if b == 0 then Nothing else Just (div ab) foo :: String -> String -> Maybe Int foo ab = case maybeE of Nothing -> Nothing Just e -> case maybeC of Nothing -> Nothing Just c -> maybeResult2args ec where maybeA :: Maybe Int maybeA = readMaybe a maybeB :: Maybe Int maybeB = readMaybe b maybeC :: Maybe Int maybeC = safePure1arg maybeB maybeD :: Maybe Int maybeD = safePure2args maybeA maybeC maybeE = case maybeA of Nothing -> Nothing Just a1 -> case maybeD of Nothing -> Nothing Just d -> maybeResult2args a1 d printMaybe :: Show a => Maybe a -> IO () printMaybe Nothing = print "Something Wrong" printMaybe (Just a) = print a main :: IO () main = do putStrLn "Input a: " a <- getLine putStrLn "Input b: " b <- getLine printMaybe (foo ab)
fmap
function exists. class Functor f where fmap :: (a -> b) -> fa -> fb
(<$>) :: Functor f => (a -> b) -> fa -> fb (<$>) = fmap
fmap id == id
fmap (f . g) == fmap f . fmap g
id
is an identity function id :: a -> a id x = x
(.)
- functional composition (.) :: (b -> c) -> (a -> b) -> a -> c f . g = \x -> f (gx)
fmap
. Let's look at its arguments - it takes one “pure” function a -> b
, we take the “dirty” functor value fa
and get the output functor value fb
.Maybe
is a functor. Create an instance (instance) for the type Maybe
, so that the laws of the functors are not violated: instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (fa)
Maybe
functor? Very simple: safePure1arg :: Maybe Int -> Maybe Int safePure1arg = fmap pure1arg
pure1arg
function, which means we don’t have to test it again for bugs and everything remained universal and clean, but we easily created its safe version, which accepts not numbers for input, but simple ones numberssafePure2args
, we’ll be a fiasco.pure
and (<*>)
class Functor f => Applicative f where pure :: a -> fa (<*>) :: f (a -> b) -> fa -> fb
pure id <*> v == v
pure (.) <*> u <*> v <*> w == u <*> (v <*> w)
pure f <*> pure x == pure (fx)
u <*> pure y == pure ($ y) <*> u
f (a -> b)
through the functor value. instance Applicative Maybe where pure = Just Nothing <*> _ = Nothing _ <*> Nothing = Nothing (Just f) <*> (Just a) = Just (fa)
safePure2args
.fmap
for the first argument, and the applicative stringing of the remaining arguments: safePure2args :: Maybe Int -> Maybe Int -> Maybe Int safePure2args ab = pure2args <$> a <*> b
safePure2args :: Maybe Int -> Maybe Int -> Maybe Int safePure2args ab = (pure pure2args) <*> a <*> b
maybeE
with the help of applicative functors? Alas.maybeResult2args
function:maybeResult2args :: Int -> Int -> Maybe Int
return
and (>>=)
functions class Monad m where return :: a -> ma (>>=) :: ma -> (a -> mb) -> mb
return a >>= k == ka
m >>= return == m
m >>= (\x -> kx >>= h) == (m >>= k) >>= h
(=<<) :: Monad m => (a -> mb) -> ma -> mb (=<<) = flip (>>=)
flip :: (a -> b -> c) -> b -> a -> c flip fab = fba
Maybe
type is a monad, which means we can define its instance (instance): instance Monad Maybe where return = Just (Just x) >>= k = kx Nothing >>= _ = Nothing
pure == return
fmap f xs == xs >>= return . f
maybeE
maybeE = maybeA >>= (\a1 -> maybeD >>= (maybeResult2args a1))
bind2
function bind2 :: Monad m => (a -> b -> mc) -> ma -> mb -> mc bind2 mf mx my = do x <- mx y <- my mf xy
maybeE = bind2 maybeResult2args maybeA maybeD
liftM2
and join
functions liftM2 :: Monad m => (a1 -> a2 -> r) -> m a1 -> m a2 -> mr join :: Monad m => m (ma) -> ma maybeE = join $ liftM2 maybeResult2args maybeA maybeD
do
notation: maybeE = do a1 <- maybeA d <- maybeD maybeResult2args a1 d
(<$>) :: Functor f => (a -> b) -> fa -> fb (<*>) :: Applicative f => f (a -> b) -> fa -> fb (=<<) :: Monad f => (a -> fb) -> fa -> fb
module Main where import Control.Monad import Control.Applicative import Text.Read (readMaybe) bind2 :: Monad m => (a -> b -> mc) -> ma -> mb -> mc bind2 mf mx my = do x <- mx y <- my mf xy pure2args :: Int -> Int -> Int pure2args = (+) pure1arg :: Int -> Int pure1arg = (+ 1) maybeResult2args :: Int -> Int -> Maybe Int maybeResult2args ab = if b == 0 then Nothing --safe else Just (div ab) foo :: String -> String -> Maybe Int foo ab = bind2 maybeResult2args maybeE maybeC where maybeA :: Maybe Int maybeA = readMaybe a --safe maybeB :: Maybe Int maybeB = readMaybe b --safe maybeC :: Maybe Int maybeC = fmap pure1arg maybeB maybeD :: Maybe Int maybeD = pure2args <$> maybeA <*> maybeC maybeE :: Maybe Int maybeE = bind2 maybeResult2args maybeA maybeD printMaybe :: Show a => Maybe a -> IO () printMaybe Nothing = print "Something Wrong" printMaybe (Just a) = print a main :: IO () main = do putStrLn "Input a: " a <- getLine putStrLn "Input b: " b <- getLine printMaybe (foo ab)
fmap = map
a = do c <- cs d <- ds return (zet cd)
a = [zet cd | c <- cs, d <- ds]
Source: https://habr.com/ru/post/212955/
All Articles