Skip to content

Instantly share code, notes, and snippets.

@hzhangxyz
Created May 21, 2025 08:04
Show Gist options
  • Save hzhangxyz/e2d770accdfd8f0405b1bdc1d77b93fb to your computer and use it in GitHub Desktop.
Save hzhangxyz/e2d770accdfd8f0405b1bdc1d77b93fb to your computer and use it in GitHub Desktop.
haskell.md

Monad

pure vs impure

  • pure
def add(a: int, b: int) -> int:
    return a + b

def square(a: int) -> int:
    return a * a
  • impure
def read_int() -> int:
    return int(input())

def print_int(a: int) -> None:
    print(a)
    return None

Functions in Haskell or ...

All functions are pure

add :: Integer -> Integer -> Integer
add = \a -> \b -> a + b

square :: Integer -> Integer
square = \a -> a * a

tips: currify, $(N \times N) \to N$ to $N \to N \to N$

tips: type can be infered automatically

IO in Haskell

What about IO function???

an example:

main = do
    putStrLn "Greetings!  What is your name?"
    inpStr <- getLine
    putStrLn $ "Welcome to Haskell, " ++ inpStr ++ "!"

do?? it is syntax sugar

let's take a even simpler example

main = putStrLn "Hello World"

what is putStrLn??

putStrLn :: String -> IO ()

tips: () is unit type, it has only a single value () :: ()

So what is IO then?

type IO :: * -> *

where * is just type, so IO is a mapping from type to type

more example...

type Integer :: *
type [] :: * -> *
type Maybe :: * -> *
type Maybe Integer :: *

IO is a monad

IO?

Imagine, all the world out side of the program is named World, so maybe we can set...

putStrLn :: String -> World -> World
getLine :: World -> (World, String)

then we can concat all IO operator one by one like a pipe.

But how to abstract them ?

if we set

IO a = World -> (World, a)

then we have

putStrLn :: String -> IO ()
getLine :: IO String

Great!

More about state

Sometimes we do not want set all the world as the state, but specific data structure.

type Control.Monad.State.State :: * -> * -> *

For any type a, Control.Monad.State.State a :: * -> * is a monad.

For example

Control.Monad.State.State Integer :: * -> *

which map a type to another type operating on a integer as the state.

So ... What is monad???

type Functor :: (* -> *) -> Constraint
class Functor f where
  fmap :: (a -> b) -> f a -> f b
-- Functors must preserve identity morphisms
-- fmap id = id
-- Functors preserve composition of morphisms
-- fmap (f . g)  ==  fmap f . fmap g

type Monad :: (* -> *) -> Constraint
class Monad m where
  (>>=)  :: m a -> (a -> m b) -> m b
  (>>)   :: m a -> m b        -> m b
  return :: a                 -> m a
-- return a >>= k                  =  k a
-- m        >>= return             =  m
-- m        >>= (\x -> k x >>= h)  =  (m >>= k) >>= h

-- every monad is also a functor
-- fmap fab ma = ma >>= (return . fab)

Examples

helloWorld :: IO ()
helloWorld = (putStr "Hello") >> (putStr "World") >> (return 2333) >> (putStrLn "!!!")

echo :: IO ()
echo = (getLine) >>= \x -> (putStrLn x)

Syntax suger

helloWorld :: IO ()
helloWorld = do
    putStr "Hello"
    putStr "World"
    putStrLn "!!!"

echo :: IO ()
echo = do
    x <- getLine
    putStrLn x

for other monad ...

import Control.Monad.State

stateOperation :: State Int Int
stateOperation = do
    modify (\x -> x + 1)
    get

runState stateOperation 0
runState (stateOperation >> stateOperation) 0

Monad transformers

What if multiple monad combined?? -> Monad Transformer

import Control.Monad.State
import System.IO

singleUpdate :: StateT Int IO ()
singleUpdate = do
    input <- liftIO readLn
    modify (+ input)
    currentState <- get
    liftIO $ putStrLn $ show currentState

multipleUpdate :: StateT Int IO ()
multipleUpdate = do
    singleUpdate
    singleUpdate
    singleUpdate
    singleUpdate
    singleUpdate

main :: IO ()
main = do
    finalState <- execStateT multipleUpdate 0
    return ()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment