我在codewar中做了一个与Haskell相关的问题,这个问题是为着名的神秘语言Brainfuck写一个解释器。Haskell的Brainfuck译员
最初,我正在考虑使用Array
来编写程序。在我开始实施解释器之后,立即意识到解释器的效率会很低,因为阵列有很多变化。然后我开始使用STArray
。但除了保存一组数据指针外,我还需要输出String
的可变引用,这在STArray
中是不可能的。所以我完全惊呆了。
写一个monadic解析器可能是一个好主意,我当时想。但事实证明,我不知道我应该用什么样的表情来模拟问题。我只阅读了一些关于monadic解析风格的论文,仅此而已。 Brainfuck比天真Add
和Minus
等复杂得多
任何指导解决这个问题,表示赞赏。以下是我的代码。我只是在这里发布它来显示代码是多么混乱。不要试图编译它,因为它充满了类型错误。
executeString' :: String -> String -> Maybe String
executeString' [] _ = Just ""
executeString' "," _ = Nothing
-- executeString' source input = Just $ map chr $ elems $ consume
length' ::String -> Int
length' source = right - left
where step (l, r) '>' = (l, r+1)
step (l, r) '<' = (l+1, r)
(left, right) = foldl' step (0, 0) source
-- decrement the data pointer
neverMinus :: Int -> Int
neverMinus n = if n == 0 then 255 else n - 1
-- increment the data pointer
alwaysPlus :: Int -> Int
alwaysPlus n = if n == 255 then 0 else n + 1
consume :: String -> String -> (Array Int Int, Array Int Char)
consume source input = runSTArray $ do
pointer <- newArray (0, arrlength') 0
forM_ source $ \t -> do
pointed <- readArray pointer point
elem <- readArray pointer pointed
isWrong <- readArray pointer error
status' <- readArray pointer status
when (1 == isWrong) $ return 0
when (doJump status') $ return 0
case t of
'>' -> writeArray pointer point (pointed + 1)
'<' -> writeArray pointer point (pointed - 1)
'+' -> writeArray pointer pointed (alwaysPlus elem)
'-' -> writeArray pointer pointed (neverMinus elem)
',' -> do index <- readArray pointer inputIndex
writeArray pointer pointed (ord $
head . drop index input)
writeArray pointer inputIndex (index+1)
1
'[' -> writeArray pointer status jump
']' -> writeArray pointer status execute
return pointer
where arrlength' = length'' + 4
length'' = length' source
strlength' = 1 + foldl' (\count s -> case s of
'.' -> count + 1) 0 source
point = length'' + 1
inputIndex = length'' + 2
status = length'' + 3 -- should the program execute current instruction or jump
error = length'' + 4 -- if there is program error during execution
-- Program status
jump = 1
execute = 0
doJump :: Int -> Bool
doJump jump = True
duJump execute = False
[这里有一些灵感](https://codereview.stackexchange.com/questions/128833/charmander-brainfuck-interpreter-in-haskell)。 – Zeta
Brainfuck不如典型的算术分析器复杂。这相当于只有一个运算符和括号。这里有一个解析器适合这个评论:'import Text.Parsec;导入Text.Parsec.Char;数据BF = Op Char |循环[BF]导出显示; main = let list = many cmd; cmd = Op <$> oneOf“<> + - 。,”<|> loop;在putStrLn中循环= char'['*>(循环<$>列表)<* char']'。显示$ runParser列表()“”“[ - > + <]”' –
这两个评论是值得的---重量---字符数在黄金,但我仍然投票关闭此为*不清楚你'再问*。 –