Difference between revisions of "PFP Laboratory 8"

From Marek Běhálek Wiki
Jump to navigation Jump to search
Line 1: Line 1:
 
== Monads ==
 
== Monads ==
 +
* Create a type
 +
<syntaxhighlight lang="Haskell">
 +
type SimpleState s a = s -> (s, a)
 +
</syntaxhighlight>
 +
Implement the ''monadic'' functions <code>return</code> and <code>bind</code>
 +
 +
<div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution">
 +
<syntaxhighlight lang="Haskell">
 +
retSt :: a -> SimpleState s a
 +
retSt a = \s -> (s,a)
 +
 +
readInt :: ListInput Int
 +
readInt stateList = (tail stateList, head stateList)
 +
 +
bind :: (s -> (s,a))        -- step
 +
    -> (a -> (s -> (s, b))) -- makeStep
 +
    -> s -> (s, b)          -- (makeStep result) newState
 +
bind step makeStep oldState =
 +
    let (newState, result) = step oldState
 +
    in  (makeStep result) newState
 +
</syntaxhighlight>
 +
</div>
 +
<div style="clear:both"></div>
 +
 +
* Define a new type and a function:
 +
<syntaxhighlight lang="Haskell">
 +
type ListInput a = SimpleState [Int] a
 +
 +
readInt :: ListInput Int
 +
readInt stateList = (tail stateList, head stateList)
 +
</syntaxhighlight>
 +
Use the previously defined functions to ''bind'' actions <code>readInt</code>.
  
 
* Consider you have a type:
 
* Consider you have a type:
Line 9: Line 41:
 
<div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution">
 
<div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution">
 
<syntaxhighlight lang="Haskell">
 
<syntaxhighlight lang="Haskell">
...
+
newtype State s a = State { runState :: s -> (s, a) }
 +
 
 +
instance Functor (State s) where
 +
    fmap f m = State $ \s-> let (s',a) = runState m s in (s',f a)
 +
 
 +
instance Applicative (State s) where
 +
    pure a = State (\s->(s,a))
 +
    f <*> m = State $ \s-> let  (s',f') = runState f s
 +
                                (s'',a) = runState m s' in (s'',f' a)
 +
 
 +
instance Monad (State s ) where
 +
    return a = State (\s->(s,a))
 +
    m >>= k = State $ \s -> let (s',a) =  runState m s in runState (k a) s'
 +
</syntaxhighlight>
 +
</div>
 +
<div style="clear:both"></div>
 +
 
 +
* Define a function <code>readInt'</code>, so that following code will be valid:
 +
<syntaxhighlight lang="Haskell">
 +
add :: State [Int] Int
 +
add = do x<-readInt'
 +
        y<-readInt'
 +
        return (x+y)
 +
</syntaxhighlight>
 +
Make this type the instance of <code>Monad</code>
 +
 
 +
<div class="mw-collapsible mw-collapsed" data-collapsetext="Hide solution" data-expandtext="Show solution">
 +
<syntaxhighlight lang="Haskell">
 +
readInt' :: State [Int] Int
 +
readInt' = State {runState = \s->(tail s, head s)}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
</div>
 
</div>
 
<div style="clear:both"></div>
 
<div style="clear:both"></div>

Revision as of 08:38, 24 October 2022

Monads

  • Create a type
type SimpleState s a = s -> (s, a)

Implement the monadic functions return and bind

retSt :: a -> SimpleState s a
retSt a = \s -> (s,a)

readInt :: ListInput Int
readInt stateList = (tail stateList, head stateList)

bind :: (s -> (s,a))         -- step
     -> (a -> (s -> (s, b))) -- makeStep
     -> s -> (s, b)          -- (makeStep result) newState
bind step makeStep oldState =
    let (newState, result) = step oldState
    in  (makeStep result) newState
  • Define a new type and a function:
type ListInput a = SimpleState [Int] a

readInt :: ListInput Int
readInt stateList = (tail stateList, head stateList)

Use the previously defined functions to bind actions readInt.

  • Consider you have a type:
newtype State s a = State { runState :: s -> (s, a) }

Make this type the instance of Monad

newtype State s a = State { runState :: s -> (s, a) } 

instance Functor (State s) where
    fmap f m = State $ \s-> let (s',a) = runState m s in (s',f a)

instance Applicative (State s) where
    pure a = State (\s->(s,a))
    f <*> m = State $ \s-> let  (s',f') = runState f s
                                (s'',a) = runState m s' in (s'',f' a)

instance Monad (State s ) where
    return a = State (\s->(s,a))
    m >>= k = State $ \s -> let (s',a) =  runState m s in runState (k a) s'
  • Define a function readInt', so that following code will be valid:
add :: State [Int] Int
add = do x<-readInt'
         y<-readInt'
         return (x+y)

Make this type the instance of Monad

readInt' :: State [Int] Int
readInt' = State {runState = \s->(tail s, head s)}