Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/hadoop/6.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 Forth口译员_Haskell - Fatal编程技术网

Haskell Forth口译员

Haskell Forth口译员,haskell,Haskell,我最近开始学习Haskell,我正试图用Haskell为第四语言编写一个解释器。但我在尝试运行最基本的操作时遇到了问题。例如,FORTH中的一个简单程序(在Haskell中作为字符串)如下:“12+”返回一个包含整数3的堆栈,在Haskell中,整数3可以表示为整数:[3]的列表 我还具有从堆栈中推、放和弹出元素的功能。我有一个加法函数,可以从堆栈中添加两个元素 现在,有了这些函数,我如何解析简单的程序“12+”以返回[3]?我希望示例如下所示: forthInterpreter "1 2 +"

我最近开始学习Haskell,我正试图用Haskell为第四语言编写一个解释器。但我在尝试运行最基本的操作时遇到了问题。例如,FORTH中的一个简单程序(在Haskell中作为字符串)如下:“12+”返回一个包含整数3的堆栈,在Haskell中,整数3可以表示为整数:[3]的列表

我还具有从堆栈中推、放和弹出元素的功能。我有一个加法函数,可以从堆栈中添加两个元素

现在,有了这些函数,我如何解析简单的程序“12+”以返回[3]?我希望示例如下所示:

forthInterpreter "1 2 +"
[3]
任何帮助都将不胜感激。如果您有任何澄清问题,请告诉我。
谢谢。

您拥有的每个命令都是来自
Stack->Stack
的函数。这使得解释命令变得容易。我使用
[Int]
作为
堆栈的类型,堆栈顶部的数字位于列表的顶部

interpretCommand :: String -> [Int] -> [Int]
interpretCommand "+" = lift2 (+)
interpretCommand "-" = lift2 (-)
interpretCommand "*" = lift2 (*)
interpretCommand "/" = lift2 div
interpretCommand "MOD" = lift2 mod
interpretCommand number = \zs -> read number : zs
其中
lift2
将2参数函数提升为列表前2个元素上的函数。参数
x
y
被交换,因为推到堆栈上的第一个参数是函数的第一个参数,堆栈顶部的参数是函数的第二个参数

lift2 :: (a -> a -> a) -> [a] -> [a]
lift2 f (x:y:zs) = f y x:zs
lift2 f _ = error "not enough data on the stack"
为了解释多个命令,我们用
单词
将它们分开,在空白处拆分一个字符串,解释每个命令,然后将它们组合在一起

composition :: [a -> a] -> a -> a
composition = foldl (flip (.)) id

interpretCommands :: String -> [Int] -> [Int]
interpretCommands = composition . map interpretCommand . words
然后我们可以通过调用
interpretactcommands
并将初始(空)堆栈传递给它来解释一个命令字符串。下面是你的两个例子

main = do
    print $ interpretCommands "1 2 +" []
    print $ interpretCommands "1 2 + 4 - 3" []
    print $ interpretCommands "10 5 / 3" []
    print $ interpretCommands "13 7 MOD 2 / 4 *" []
输出是

[3]
[3,-1]
[3,2]
[12]

请注意,
[3,-1]
的顺序与您建议的相反,因为
3
位于堆栈顶部,因此位于列表的开头。(这是您在
fourthadd
中的注释中预测的行为)

您拥有的每个命令都是
Stack->Stack
中的函数。这使得解释命令变得容易。我使用
[Int]
作为
堆栈的类型,堆栈顶部的数字位于列表的顶部

interpretCommand :: String -> [Int] -> [Int]
interpretCommand "+" = lift2 (+)
interpretCommand "-" = lift2 (-)
interpretCommand "*" = lift2 (*)
interpretCommand "/" = lift2 div
interpretCommand "MOD" = lift2 mod
interpretCommand number = \zs -> read number : zs
其中
lift2
将2参数函数提升为列表前2个元素上的函数。参数
x
y
被交换,因为推到堆栈上的第一个参数是函数的第一个参数,堆栈顶部的参数是函数的第二个参数

lift2 :: (a -> a -> a) -> [a] -> [a]
lift2 f (x:y:zs) = f y x:zs
lift2 f _ = error "not enough data on the stack"
为了解释多个命令,我们用
单词
将它们分开,在空白处拆分一个字符串,解释每个命令,然后将它们组合在一起

composition :: [a -> a] -> a -> a
composition = foldl (flip (.)) id

interpretCommands :: String -> [Int] -> [Int]
interpretCommands = composition . map interpretCommand . words
然后我们可以通过调用
interpretactcommands
并将初始(空)堆栈传递给它来解释一个命令字符串。下面是你的两个例子

main = do
    print $ interpretCommands "1 2 +" []
    print $ interpretCommands "1 2 + 4 - 3" []
    print $ interpretCommands "10 5 / 3" []
    print $ interpretCommands "13 7 MOD 2 / 4 *" []
输出是

[3]
[3,-1]
[3,2]
[12]

请注意,
[3,-1]
的顺序与您建议的相反,因为
3
位于堆栈顶部,因此位于列表的开头。(这是您在
fourthadd
中的评论中预测的行为)

与Cirdec的答案相同,但对于初学者来说,这可能更容易阅读:

-- Data type to represent a command.
data Command = Push Int | Add | Subtract deriving Show

-- Type synonym: a Program is a list of commands.
type Program = [Command]

-- Type synonym: a Stack is a list of Int.
type Stack = [Int]

-- The interpreter entry point.
interpretCommands :: String -> Int
interpretCommands str = runProgram (parseProgram str)

-- Parse a string and turn it into the corresponding Program.
parseProgram :: String -> Program
parseProgram str = map toCommand (words str)
    where toCommand "+" = Add
          toCommand "-" = Subtract
          toCommand x = Push (read x)

-- Run a Program on the empty stack, return the result at the top of the result stack.
runProgram :: Program -> Int
runProgram program = head (runProgram' program [])

-- Run a program on a given stack, return the result stack.
runProgram' :: Program -> Stack -> Stack
runProgram' [] stack = stack
runProgram' (command:rest) stack = runProgram' rest (runCommand command stack)

-- Run an individual command.
runCommand :: Command -> Stack -> Stack
runCommand (Push n) stack = n:stack
runCommand Add (n:m:stack) = n+m:stack
runCommand Subtract (n:m:stack) = n-m:stack

我将程序分为两部分:
parser
runProgram
。第一种方法获取字符串并将其转换为要运行的程序的抽象表示形式。第二种解释这种抽象的表达。在这样的问题中,这是一个很好的分离;例如,当您希望编写更好的解析逻辑时,您可以修改
解析器
,而不必担心破坏
运行程序
逻辑。

与Cirdec的答案相同,但对于初学者来说,这可能更容易阅读:

-- Data type to represent a command.
data Command = Push Int | Add | Subtract deriving Show

-- Type synonym: a Program is a list of commands.
type Program = [Command]

-- Type synonym: a Stack is a list of Int.
type Stack = [Int]

-- The interpreter entry point.
interpretCommands :: String -> Int
interpretCommands str = runProgram (parseProgram str)

-- Parse a string and turn it into the corresponding Program.
parseProgram :: String -> Program
parseProgram str = map toCommand (words str)
    where toCommand "+" = Add
          toCommand "-" = Subtract
          toCommand x = Push (read x)

-- Run a Program on the empty stack, return the result at the top of the result stack.
runProgram :: Program -> Int
runProgram program = head (runProgram' program [])

-- Run a program on a given stack, return the result stack.
runProgram' :: Program -> Stack -> Stack
runProgram' [] stack = stack
runProgram' (command:rest) stack = runProgram' rest (runCommand command stack)

-- Run an individual command.
runCommand :: Command -> Stack -> Stack
runCommand (Push n) stack = n:stack
runCommand Add (n:m:stack) = n+m:stack
runCommand Subtract (n:m:stack) = n-m:stack

我将程序分为两部分:
parser
runProgram
。第一种方法获取字符串并将其转换为要运行的程序的抽象表示形式。第二种解释这种抽象的表达。在这样的问题中,这是一个很好的分离;例如,当您希望编写更好的解析逻辑时,您可以修改
解析器
,而不必担心破坏
运行程序
逻辑。

为什么需要
组合中的
翻转
?与此相关的是,您将如何扩展(或修改)代码以使division和mod操作正常工作?在上面,您必须使用
substract
来获得正确的减法行为。感谢您将两个函数组合在一起。g
g
首先应用,然后是
f
foldl
按该顺序将函数重复应用于累积值和列表的第一个值。例如,
foldl op 0[1,2,3]
((0'op'1)'op'2)'op'3
。如果我们有一个函数列表
[f,g,h,i,j]
,我们想把它们组合在一起,首先执行
f
,那就是
j。我HGf
,顺序相反
flip
将参数的顺序翻转到
@user178332如何添加除法取决于操作数被推送到堆栈的顺序。您希望它们的顺序是什么?因此
“10 5/3”
应该返回[3,2]您似乎忘记了实际交换
lift2
中的参数。为什么需要
组合中的
翻转
?与此相关的是,您将如何扩展(或修改)代码以使division和mod操作正常工作?在上面,您必须使用
substract
来获得正确的减法行为。感谢您将两个函数组合在一起。g
g
首先应用,然后是
f
foldl
对累积值重复应用该函数