Trampolineモナド
トランポリンモナド
#WIP
https://pursuit.purescript.org/packages/purescript-free/4.0.0/docs/Control.Monad.Trampoline
使い方
仕組み
#??
Effectとどうやって組み合わせる?
delayってなに?
実装が異なる
https://github.com/purescript/purescript-free/blob/v4.0.0/src/Control/Monad/Trampoline.purs#L24-L24
v4
Free Lazy
https://github.com/purescript/purescript-free/pull/85
https://github.com/purescript/purescript-free/issues/83
https://github.com/purescript/purescript-free/blob/master/src/Control/Monad/Trampoline.purs
master
Free ((->) Unit)
Stackless Scala With Free Monads
Stack Safety for Free
https://eed3si9n.com/herding-cats/ja/tail-recursive-monads.html
例
元の実装
code:purs(hs)
-- countDown :: Int -> Int
-- countDown 1 = 1
-- countDown n = countDown $ n - 1
-- g = countDown 300000
これでは別にStack Over Flowはしない
コンパイル後のJS見ればわかるが、ちゃんと末尾再帰の最適化されている
ここにlogを仕込むとStack Over Flowするようになる
Effectにしただけでは最適化されているが、logが入ると落ちる
code:purs(hs)
-- countDown :: Int -> Effect Int
-- countDown 1 = pure 1
-- countDown n = do
-- log $ show n
-- countDown $ n - 1
-- g = countDown 30000
使い方としてはこんな感じ
もともとStack Over Flowしてないので、意味ない
例が悪い
が、使い方の雰囲気としてはこんなかんじだということがわかる
code:purs(hs)
countDown :: Int -> Trampoline Int
countDown 1 = done 1
countDown n = countDown (n - 1)
f = runTrampoline $ countDown 100000
じゃあ、trampolineしつつ、log出すのってどうやるの #??
code:purs(hs)
countDown :: Int -> Trampoline (Effect Unit)
-- countDown 1 = done $ liftEffect $ pure 1
countDown 1 = done $ liftEffect $ log "1"
countDown n = do
-- liftEffect $ delay $ log $ show n
_ <- delay $ \_ -> log $ show n
countDown (n - 1)
f = runTrampoline $ countDown 100000
ちょっと行き詰まっている
コンパイル後のJSにlog仕込めばちゃんと100000回loopしているのがわかる
これでいけた
code:purs(hs)
module Prac5 where
import Prelude
import Control.Monad.Free.Trans (FreeT, runFreeT)
import Control.Monad.Rec.Class (class MonadRec)
import Data.Identity (Identity(..))
import Effect (Effect)
import Effect.Class (liftEffect)
import Effect.Class.Console (log)
runIdentity :: forall a. Identity a -> a
runIdentity (Identity a) = a
type SafeT = FreeT Identity
runSafeT :: forall m a. (MonadRec m) => SafeT m a -> m a
runSafeT = runFreeT (pure <<< runIdentity)
countDown :: Effect Unit
countDown = runSafeT $ go 100000
where
go :: Int -> SafeT Effect Unit
go 1 = pure unit
go n = do
liftEffect (log $ show n)
go (n-1)
いや、Trampoline使わんのかい、となったmrsekut.icon
いや、Trampolineにwrapできるのかこれ
trunSafeTがrunTrampolineみたいなものか
これ、TrampolineTみたいなものがいるのでは?
https://pursuit.purescript.org/packages/purescript-freet/6.0.0/docs/Control.Monad.Free.Trans