Last active
November 7, 2019 00:32
-
-
Save HirotoShioi/78abbb622988b00c54924435dcb056ff to your computer and use it in GitHub Desktop.
モナド変換子(その1: 基本) ref: https://qiita.com/HirotoShioi/items/8a6107434337b30ce457
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
someFun :: Env -> IO () | |
... | |
someHandling :: Env -> Int -> IO Int | |
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Somedataを処理する関数 | |
someFun :: SomeData -> Either String SomeData | |
.... | |
-- SomeDataからIntを算出する関数 | |
someEither :: SomeData -> Either String Int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> Int | |
eval (Lit n) = n | |
eval (Add e1 e2) = eval e1 + eval e2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ: eval (Add (Add (Lit 3) (Lit 4)) (Lit 10)) | |
17 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data Expr = | |
Lit Int | |
| Add Expr Expr | |
| Div Expr Expr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> Int | |
eval (Lit n) = n | |
eval (Add e1 e2) = eval e1 + eval e2 | |
eval (Div e1 e2) = eval e1 `div` eval e2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ:eval (Div (Lit 10) (Lit 0)) | |
*** Exception: divide by zero |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> Either String Int | |
eval (Lit n) = pure n | |
eval (Add e1 e2) = (+) <$> eval e1 <*> eval e2 | |
eval (Div e1 e2) = do | |
v1 <- eval e1 | |
v2 <- eval e2 | |
if v2 == 0 | |
then Left "division by 0" | |
else return (v1 `div` v2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> ??? Int | |
eval :: (Lit n) = pure n | |
eval :: (Add e1 e2) = (+) <$> eval e1 <*> eval e2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> Identity Int | |
eval (Lit n) = pure n | |
eval (Add e1 e2) = (+) <$> eval e1 <*> eval e2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ: runIdentity $ eval (Add (Lit 10) (Lit 7)) | |
17 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> ExceptT String Identity Int | |
eval (Lit n) = pure n | |
eval (Add e1 e2) = (+) <$> eval e1 <*> eval e2 | |
eval (Div e1 e2) = do | |
v1 <- eval e1 | |
v2 <- eval e2 | |
if v2 == 0 | |
then throwError "division by 0" | |
else return (v1 `div` v2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
newtype ErrorState a = ErrorState { runErrorState :: s -> Either String (a, s) } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
run :: Expr -> Either String Int | |
run expr = runIdentity (runExceptT (eval expr)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data Expr = | |
Lit Int | |
| Add Expr Expr | |
| Div Expr Expr | |
| Var String |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Env = Map String Int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> ReaderT Env (ExceptT String Identity) Int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Eval = ReaderT Env (ExceptT String Identity) Int | |
-- or | |
newtype Eval a = Eval (ReaderT Env (ExceptT String Identity) a) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Message = String | |
newtype Message = Message String |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
someFun :: Message -> Maybe Char |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Why? | |
evilFun :: Message -> Char | |
evilFun = head |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
newtype Message = Message String | |
-- Stringとは全く別の型クラスインスタンスが実装可能 | |
instance Show Message where | |
show msg = "New typeclass instance for show" <> show msg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
newtype Eval a = Eval (ExceptT String Identity) a | |
deriving (???) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
instance Monad (ErrorState e) where | |
return a = ErrorState $ \s -> Right (a, s) | |
m >>= cont = ErrorState $ \s -> case runErrorState m s of | |
(Left e) -> Left e | |
(Right (a, s')) -> runErrorState (cont a) s' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |
newtype Quantity = Quantity Int | |
deriving (Eq, Ord, Num, Show) | |
a = Quantity 2 | |
b = Quantity 6 | |
totalQuantity :: Quantity | |
totalQuantity = a + b | |
-- Quantity 8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class (Monad m) => MonadReader r m | m -> r where | |
ask :: m r | |
local :: (r -> r) -> m a -> m a | |
instance (Monad m) => MonadReader r (ReaderT r m) where | |
ask = ReaderT return | |
local f m = ReaderT $ \r -> runReaderT m (f r) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
newtype App a = App (ReaderT [Int] (Either String) a) | |
deriving (Functor | |
, Applicative | |
, Monad | |
, MonadReader [Int]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
newtype Eval a = Eval (ReaderT Env (ExceptT String Identity) a) | |
deriving (Functor | |
, Applicative | |
, Monad | |
, MonadReader Env | |
, MonadError String) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval :: Expr -> Eval Int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
runEval :: Eval a -> Env -> Either String a | |
runEval (Eval m) env = runIdentity (runExceptT (runReaderT m env)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval (Var x) = do | |
env <- ask | |
case M.lookup x env of | |
Nothing -> throwError $ "Variable not found: " <> show x | |
Just num -> pure num |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ: runEval (eval (Add (Var "x") (Lit 10))) (singleton "x" 10) | |
Right 20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data Expr = | |
Lit Int | |
| Add Expr Expr | |
| Div Expr Expr | |
| Var String | |
| Seq Expr Expr | |
| Assign String Expr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Before (ReaderT) | |
newtype Eval a = Eval (ReaderT Env (ExceptT String Identity) a) | |
deriving (Functor, Applicative, Monad, MonadReader Env, MonadError String) | |
-- After (StateT) | |
newtype Eval a = Eval (StateT Env (ExceptT String Identity) a) | |
deriving (Functor, Applicative, Monad, MonadState Env, MonadError String) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
instance Functor (ErrorState e) where | |
fmap = liftM | |
instance Applicative (ErrorState e) where | |
pure = return | |
(<*>) = ap |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Before (ReaderT) | |
runEval :: Eval a -> Env -> Either String a | |
runEval (Eval m) env = runIdentity (runExceptT (runReaderT m env)) | |
-- After (StateT) | |
runEval :: Eval a -> Env -> Either String a | |
runEval (Eval m) env = runIdentity (runExceptT (evalStateT m env)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval (Var x) = do | |
env <- get -- ask | |
case M.lookup x env of | |
Nothing -> throwError $ "Variable not found: " <> show x | |
Just num -> pure num |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval (Seq e1 e2) = e1 >> e2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
eval (Assign x e) = do | |
v <- eval e | |
modify (M.insert x v) | |
return v |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
program :: Expr | |
program = Assign "x" (Lit 10) | |
`Seq` Assign "x" (Div (Var "x") (Lit 2)) | |
`Seq` Add (Var "x") (Lit 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let x = 10; | |
x = x / 2; | |
console.log (x + 1); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ: runEval (eval program) empty | |
Right 6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE GeneralizedNewtypeDeriving #-} | |
module Interpreter where | |
import Control.Monad.Identity | |
import Control.Monad.Except | |
import Control.Monad.State | |
import Data.Map | |
import qualified Data.Map as M | |
import Data.Monoid ((<>)) | |
type Env = Map String Int | |
data Expr = | |
Lit Int | |
| Add Expr Expr | |
| Div Expr Expr | |
| Var String | |
| Assign String Expr | |
| Seq Expr Expr | |
newtype Eval a = Eval (StateT Env (ExceptT String Identity) a) | |
deriving (Functor, Applicative, Monad, MonadState Env, MonadError String) | |
eval :: Expr -> Eval Int | |
eval (Lit n) = pure n | |
eval (Add e1 e2) = (+) <$> eval e1 <*> eval e2 | |
eval (Div e1 e2) = doDiv e1 e2 | |
eval (Var x) = varLookup x | |
eval (Seq e1 e2) = eval e1 >> eval e2 | |
eval (Assign x e) = varSet x e | |
doDiv :: Expr -> Expr -> Eval Int | |
doDiv e1 e2 = do | |
v1 <- eval e1 | |
v2 <- eval e2 | |
if v2 == 0 | |
then divByZeroError | |
else return (v1 `div` v2) | |
divByZeroError :: Eval a | |
divByZeroError = throwError "Division by 0" | |
varLookup :: String -> Eval Int | |
varLookup x = do | |
env <- get | |
case M.lookup x env of | |
Nothing -> unknownVar x | |
Just num -> return num | |
varSet :: String -> Expr -> Eval Int | |
varSet x e = do | |
v <- eval e | |
modify (M.insert x v) | |
return v | |
unknownVar :: String -> Eval a | |
unknownVar x = throwError $ "Variable not found: " <> show x | |
runEval :: Eval a -> Env -> Either String a | |
runEval (Eval m) env = runIdentity (runExceptT (evalStateT m env)) | |
program :: Expr | |
program = Assign "x" (Lit 10) | |
`Seq` Assign "x" (Div (Var "x") (Lit 2)) | |
`Seq` Add (Var "x") (Lit 1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ: runEval (eval (Add (Lit 10) (Get)) empty | |
Please enter a number | |
10 | |
Right 20 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
get :: ErrorState s s | |
get = ErrorState $ \s -> Right (s, s) | |
put :: s -> ErrorState s () | |
put = ErrorState $ \_ -> Right ((), s) | |
modify :: (s -> s) -> ErrorState s () | |
modify f = get >>= \s -> put (f s) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
throwError :: String -> ErrorState s a | |
throwError str = ErrorState $ \_ -> Left e |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
addEven :: Int -> ErrorState Int () | |
addEven num = if odd num | |
then throwError $ "Invalid number: " ++ show num | |
else modify (+ num) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
λ: runErrorState (addEven 10) 10 | |
Right ((),20) | |
λ: runErrorState (addEven 11) 10 | |
Left "Invalid number: 11" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
data Expr = | |
Lit Int | |
| Add Expr Expr |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment