I have this problem, where I want to build an interpreter for an abstract form of the while language. In the condition of the while, I have an m Bool
which needs to be evaluated before every loop execution. However, I have not yet found a way to extract/use the boolean out of the monad. I have made a while program for a factorial function to clarify how I want to use the while. Can anybody help me figure out how to solve this?
import Polysemy
import Polysemy.State
import Prelude hiding (lookup, log)
import Data.Map
import Data.Maybe
type WhileLangState = Map String Double
data WhileLang m a where
Assign :: String -> Double -> WhileLang m ()
While :: m Bool -> m () -> WhileLang m ()
GetVar :: String -> WhileLang m Double
makeSem ''WhileLang
runWhileLang :: Member (State WhileLangState) r => Sem (WhileLang : r) a -> Sem r a
runWhileLang = interpretH $ \case
(Assign s d) -> do
state <- get
put (insert s d state)
pureT ()
(While cond body) -> do
body' <- runT body
cond' <- runT cond
let loop = do
if cond' -- how can I get the boolean?
then body' >> loop
else pure ()
_ <- pureT loop
pureT ()
(GetVar s) -> do
state <- get
pureT $ fromMaybe 0 (lookup s state)
whileFactorial :: Member WhileLang r => Sem r ()
whileFactorial = do
assign "n" 8
assign "result" 1
while ((> 0) <$> getVar "n") $ do
result <- getVar "result"
currentN <- getVar "n"
assign "result" (result * currentN)
assign "n" (currentN - 1)
I have this problem, where I want to build an interpreter for an abstract form of the while language. In the condition of the while, I have an m Bool
which needs to be evaluated before every loop execution. However, I have not yet found a way to extract/use the boolean out of the monad. I have made a while program for a factorial function to clarify how I want to use the while. Can anybody help me figure out how to solve this?
import Polysemy
import Polysemy.State
import Prelude hiding (lookup, log)
import Data.Map
import Data.Maybe
type WhileLangState = Map String Double
data WhileLang m a where
Assign :: String -> Double -> WhileLang m ()
While :: m Bool -> m () -> WhileLang m ()
GetVar :: String -> WhileLang m Double
makeSem ''WhileLang
runWhileLang :: Member (State WhileLangState) r => Sem (WhileLang : r) a -> Sem r a
runWhileLang = interpretH $ \case
(Assign s d) -> do
state <- get
put (insert s d state)
pureT ()
(While cond body) -> do
body' <- runT body
cond' <- runT cond
let loop = do
if cond' -- how can I get the boolean?
then body' >> loop
else pure ()
_ <- pureT loop
pureT ()
(GetVar s) -> do
state <- get
pureT $ fromMaybe 0 (lookup s state)
whileFactorial :: Member WhileLang r => Sem r ()
whileFactorial = do
assign "n" 8
assign "result" 1
while ((> 0) <$> getVar "n") $ do
result <- getVar "result"
currentN <- getVar "n"
assign "result" (result * currentN)
assign "n" (currentN - 1)
Share
Improve this question
edited Nov 20, 2024 at 15:00
talex
20.6k3 gold badges33 silver badges68 bronze badges
asked Nov 20, 2024 at 14:50
MorpheusMorpheus
192 bronze badges
2
|
1 Answer
Reset to default 2I'm not familiar with how polysemy works but based on the types of the API, it looks like you can use getInspectorT
to get a function f x -> Maybe x
that lets you inspect values produced by computations, getInitialState
to get an "initial state", and bindTSimple
to thread the state through the handled computation. I don't know in what situations the function returned by getInspectorT
produces Nothing
.
{-# LANGUAGE FlexibleContexts, TemplateHaskell, LambdaCase, GADTs, ScopedTypeVariables, DataKinds, TypeOperators #-}
import Polysemy
import Polysemy.State
import Prelude hiding (lookup, log)
import Data.Map
import Data.Maybe
type WhileLangState = Map String Double
data WhileLang m a where
Assign :: String -> Double -> WhileLang m ()
While :: m Bool -> m () -> WhileLang m ()
GetVar :: String -> WhileLang m Double
makeSem ''WhileLang
runWhileLang :: Member (State WhileLangState) r => Sem (WhileLang : r) a -> Sem r a
runWhileLang = interpretH $ \case
(Assign s d) -> do
state <- get
put (insert s d state)
pureT ()
(While cond body) -> do
inspector <- getInspectorT
let loop unit = do
cond' <- bindTSimple (\() -> cond) unit
if fromJust (inspect inspector cond') then
bindTSimple (\() -> body) unit >>=
loop
else
pure unit
unit <- getInitialStateT
loop unit
(GetVar s) -> do
state <- get
pureT $ fromMaybe 0 (lookup s state)
whileFactorial :: Member WhileLang r => Sem r ()
whileFactorial = do
assign "n" 8
assign "result" 1
while ((> 0) <$> getVar "n") $ do
result <- getVar "result"
currentN <- getVar "n"
assign "result" (result * currentN)
assign "n" (currentN - 1)
-- Run the example
main :: IO ()
main = runM (runState (empty :: WhileLangState) (runWhileLang whileFactorial)) >>= print
cond'
the usual way, using>>=
orb <- cond'
, or you can use something likewhileM_ cond' body
instead of reinventing the wheel. – Naïm Favier Commented Nov 20, 2024 at 17:03runT
? If it's typeclass polymorphic, which instance(s) are used (or are you hoping to be used) in the given snippet? – Daniel Wagner Commented Nov 20, 2024 at 17:12