Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell-单子转换器-限制解释器中的求值次数_Haskell_Monad Transformers_State Monad - Fatal编程技术网

Haskell-单子转换器-限制解释器中的求值次数

Haskell-单子转换器-限制解释器中的求值次数,haskell,monad-transformers,state-monad,Haskell,Monad Transformers,State Monad,我正在学习Monad Transformers,并决定为一种简单的语言(带有循环结构)编写一个解释器,类似于使用Monad Transformers的Brainfuck。我想在一定数量的陈述之后终止口译员 module Transformers where import qualified Data.Map as Map import Data.Maybe import Control.Monad.State.L

我正在学习Monad Transformers,并决定为一种简单的语言(带有循环结构)编写一个解释器,类似于使用Monad Transformers的Brainfuck。我想在一定数量的陈述之后终止口译员

module Transformers where

import qualified Data.Map                      as Map
import           Data.Maybe
import           Control.Monad.State.Lazy
import           Control.Monad.Writer.Lazy
import           Control.Monad.Except


data Term = Input
  | Output
  | Increment
  | Decrement
  | Loop [Term]
  deriving (Show)

data World = World {
  inp :: [Int],
  out :: [Int],
  mem :: Int
} deriving Show

op_limit = 5

loop
  :: [Term]
  -> StateT World (WriterT (Sum Int) (Except World)) ()
  -> StateT World (WriterT (Sum Int) (Except World)) ()
loop terms sp = sp >> do
  s <- get
  if mem s == 0 then put s else loop terms (foldM (\_ t -> eval t) () terms)

limit :: StateT World (WriterT (Sum Int) (Except World)) ()
limit = do
  (s, count) <- listen get
  when (count >= op_limit) $ throwError s

tick :: StateT World (WriterT (Sum Int) (Except World)) ()
tick = tell 1

eval :: Term -> StateT World (WriterT (Sum Int) (Except World)) ()
eval Input =
  limit >> tick >> modify (\s -> s { inp = tail (inp s), mem = head (inp s) })
eval Output       = limit >> tick >> modify (\s -> s { out = mem s : out s })
eval Increment    = limit >> tick >> modify (\s -> s { mem = mem s + 1 })
eval Decrement    = limit >> tick >> modify (\s -> s { mem = mem s - 1 })
eval (Loop terms) = loop terms (void get)

type Instructions = [Term]

interp :: Instructions -> World -> Either World (World, Sum Int)
interp insts w =
  let sp = foldM (\_ inst -> eval inst) () insts
  in  runExcept (runWriterT (execStateT sp w))
这种简单的语言是由单个存储单元组成的,能够容纳一个Int和5条指令输入、输出、递增、递减和循环。当内存中的值为零时,循环终止。输入从一个列表中读取,同样地,输出被写入另一个列表。增量和减量对应地对内存执行+1和-1操作

我使用
World
type来跟踪输入、输出(流)和内存,
Sum Int
来计算计算的指令数<代码>除世界之外在某些语句后终止计算

module Transformers where

import qualified Data.Map                      as Map
import           Data.Maybe
import           Control.Monad.State.Lazy
import           Control.Monad.Writer.Lazy
import           Control.Monad.Except


data Term = Input
  | Output
  | Increment
  | Decrement
  | Loop [Term]
  deriving (Show)

data World = World {
  inp :: [Int],
  out :: [Int],
  mem :: Int
} deriving Show

op_limit = 5

loop
  :: [Term]
  -> StateT World (WriterT (Sum Int) (Except World)) ()
  -> StateT World (WriterT (Sum Int) (Except World)) ()
loop terms sp = sp >> do
  s <- get
  if mem s == 0 then put s else loop terms (foldM (\_ t -> eval t) () terms)

limit :: StateT World (WriterT (Sum Int) (Except World)) ()
limit = do
  (s, count) <- listen get
  when (count >= op_limit) $ throwError s

tick :: StateT World (WriterT (Sum Int) (Except World)) ()
tick = tell 1

eval :: Term -> StateT World (WriterT (Sum Int) (Except World)) ()
eval Input =
  limit >> tick >> modify (\s -> s { inp = tail (inp s), mem = head (inp s) })
eval Output       = limit >> tick >> modify (\s -> s { out = mem s : out s })
eval Increment    = limit >> tick >> modify (\s -> s { mem = mem s + 1 })
eval Decrement    = limit >> tick >> modify (\s -> s { mem = mem s - 1 })
eval (Loop terms) = loop terms (void get)

type Instructions = [Term]

interp :: Instructions -> World -> Either World (World, Sum Int)
interp insts w =
  let sp = foldM (\_ inst -> eval inst) () insts
  in  runExcept (runWriterT (execStateT sp w))

monad
限制基于计数,应决定在当前状态下失败或不执行任何操作。但是我注意到
Writer
monad中的
count
计算无法访问自己的累加器。更重要的是:在计算运行时,累加器永远不会被强制,即使是WHNF也不会。这适用于
Writer
的严格变量和惰性变量-严格变量在某种意义上与累加器无关。如果计算运行时间过长,累加器中不可避免的惰性可能会导致空间泄漏


您的
limit
函数没有在“mainline”
WriterT
累加器的值上分支。
get
操作(您正在使用mtl)只是从
StateT
层读取状态,在其他层中不执行任何效果:它将
mempty
添加到其
WriterT
累加器中,并且不会抛出错误

然后,
listen
提取
get
操作的
Writer
累加器(仅是
get
的累加器,而不是整个计算的累加器),并将其添加到“主线”累加器中。但是这个提取的值(元组中返回的值)将始终是
mempty
,也就是说,
Sum 0


如@chi所述,您可以将计数器置于
StateT
状态,而不是
WriterT
。您还可以使用,这与
WriterT
非常类似,但允许您检查累加器(还允许您使用bang模式将累加器强制到WHNF)


AccumT
似乎没有相应的mtl typeclass,因此您需要喷洒一些升降机才能使用它

我只是简单地看了一下,但似乎您想阅读您的“语句数”,它目前是由编写器monad建模的。如果是这样,不要使用writer monad,因为你需要阅读。将计数器置于世界状态,然后删除writer层。