Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.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
Python 用Haskell表示非确定性有限状态机模拟器_Python_Haskell_Recursion_Functional Programming_Monads - Fatal编程技术网

Python 用Haskell表示非确定性有限状态机模拟器

Python 用Haskell表示非确定性有限状态机模拟器,python,haskell,recursion,functional-programming,monads,Python,Haskell,Recursion,Functional Programming,Monads,我正在Udacity上学习“编程语言”,并试图用Haskell来表示问题集。答案是用Python编写的: edges = {(1,"a") : [2,3] ,(2,"a") : [2] ,(3,"b") : [3,4] ,(4,"c") : [5]} accepting = [2,5] def nfsmSim(string, current, edges, accepting): if string == "": ret

我正在Udacity上学习“编程语言”,并试图用Haskell来表示问题集。答案是用Python编写的:

edges = {(1,"a") : [2,3]
        ,(2,"a") : [2]
        ,(3,"b") : [3,4]
        ,(4,"c") : [5]}

accepting = [2,5]

def nfsmSim(string, current, edges, accepting):
    if string == "":
        return current in accepting
    else:
        letter = string[0]
        key = (current, letter)
        if key in edges:
            rest = string[1:]
            states = edges[key]
            for state in states:
                if nfsmSim(rest, state, edges, accepting):
                    return True
         return False
启动状态始终是第一个状态,即
当前=1

接受诸如
“aaa”
“abc”
之类的字符串,同时接受或拒绝
“abb”
“aabc”

我尝试使用Haskell重写:

nfsmSim [] c _  = [c]
nfsmSim xs c es = [concat $ nfsmSim (tail xs) s es | (k,ss) <- es, s <- ss, x <- xs, k==(c,x)]
nfsmSim[]c[c]

nfsmSim xs c es=[concat$nfsmSim(tail xs)s es |(k,ss)让我们先考虑一下类型。您的Python函数或多或少有以下类型:

type State=Int
类型映射kv=[(k,v)]
nfsmSim::String->State->Map(Int,Char)[State]->[State]->Bool
nfsmSim字符串当前边缘接受=…
我们可以对空字符串大小写使用模式匹配:

nfsmSim::String->State->Map(Int,Char)[State]->[State]->Bool
nfsmSim“”当前uu接受=当前`元素`接受
对于非空的情况,我们执行与Python代码相同的操作:

nfsmSim(x:xs)当前边缘接受=
让rest=xs
状态=[s |(k,v)b->[a])->(a->Bool->[b]->a->Bool
nfsmSim高级接受字符串电流=go字符串电流
哪里
go[]c=接受c
go(x:xs)c=any(go-xs)(前进cx)
顺便说一下,最后一个变量仍然可以使用“边”和“接受”

nfsmSimAccept字符串当前边缘接受=
让我们接受c=c`elem`接受

advancecx=[s |(k,v)这是我的Haskell-ish方法:

我们可以使用haskell的Data.Set和Data.Map库来表示我们的状态机

import qualified Data.Map as M
import qualified Data.Set as S
让我们为状态机定义一些数据类型:

type State = Int
type Edge = (State, Char)
type Machine = (M.Map Edge (S.Set State), S.Set State)
我们这样定义机器:

myMachine :: Machine
myMachine = (M.fromList
    [ ((1, 'a'), S.fromList [2, 3])
    , ((2, 'a'), S.fromList [2   ])
    , ((3, 'b'), S.fromList [3, 4])
    , ((4, 'c'), S.fromList [5   ])
    ] , S.fromList [2, 5])
我们可以这样运行机器:

runMachine :: String -> Machine -> State -> Bool
runMachine "" (_, acceptingStates) currentState =
    S.member currentState acceptingStates
runMachine (ch:rest) machine@(edges, _) currentState =
    case M.lookup (currentState, ch) edges of
        Nothing -> False
        Just nextStates ->
            or $ S.map (runMachine rest machine) nextStates

由于函数返回一个
Bool
,因此没有很好的理由使用monad或do表示法。但是,如果我们使用类型
Maybe()
代替
Bool
,其中
只是()
表示
表示

首先,我知道,没有“非有限状态机”这样的东西。从你写的判断,我意识到它是关于“非确定性有限自动机(NFA)”

第一种变体

nfa :: String -> Int -> [((Int, Char), [Int])] -> [Int] -> Bool
nfa       [] cur     _ acc = cur `elem` acc
nfa (c:rest) cur edges acc
    | Just states <- lookup (cur, c) edges = any (\state -> nfa rest state edges acc) states
    | otherwise                            = False

edges =
    [ ((1, 'a'), [2, 3])
    , ((2, 'a'), [2])
    , ((3, 'b'), [3, 4])
    , ((4, 'c'), [5])
    ]

accepting = [2, 5]

main = do
    print $ nfa "aaa" 1 edges accepting
    print $ nfa "abc" 1 edges accepting
    print $ nfa "abb" 1 edges accepting
    print $ nfa "aabc" 1 edges accepting
第二种变体:

import Control.Monad
import Data.Maybe

nfa2 :: String -> Int -> [((Int, Char), [Int])] -> [Int] -> [Int]
nfa2       [] cur     _ acc = guard (cur `elem` acc) >> return cur
nfa2 (c:rest) cur edges acc = do
    state <- fromMaybe mzero $ lookup (cur, c) edges
    nfa2 rest state edges acc

edges =
    [ ((1, 'a'), [2, 3])
    , ((2, 'a'), [2])
    , ((3, 'b'), [3, 4])
    , ((4, 'c'), [5])
    ]

accepting = [2, 5]

main = do
    print $ nfa2 "aaa" 1 edges accepting
    print $ nfa2 "abc" 1 edges accepting
    print $ nfa2 "abb" 1 edges accepting
    print $ nfa2 "aabc" 1 edges accepting

如果可能的话,你能给这个练习添加一个链接吗?@Zeta
Set
太过分了。不需要“结束”状态是一个排序集。感谢你的解决方案。我对Haskell的理解水平很低,所以你介绍的许多概念希望在以后的过程中更有意义。感谢你纠正我的草率问题!我编辑了标题。我的想法对吗
只是状态不,这只是Haskell 2010语法“Patter guard”()感谢您提供的解决方案。您的回答正好符合我的能力,我从您的数据方法中学到了很多。顺便说一句,当我复制您的第一个解决方案并在haskell repl中运行它时,我得到了
无法将类型
Integer'与
Int'匹配的结果;预期类型:[State];实际类型:[Integer]
。我将
Int
替换为
Integer
,然后进行编译。有什么原因吗?@poton你在什么地方使用了
Integer
?我复制了原样的解决方案。可能是版本(7.6.3)最终的解决方案也遭到了反对,直到我将
b
替换为
Char
。我意识到类型系统有助于澄清我混乱的想法,但有时它的错误消息似乎有点迟钝。我想我必须更深入地研究这些消息,或者可能有一个开关这可以给出一个更详细的解释吗?@potong hm.这超出了这个问题的范围,但是你能把你的完整代码作为要点或粘贴库或类似的东西发布吗?如果没有你周围的代码,很难看出错误可能在哪里。经过一点修改,我意识到我已经在编译的c中包含了
边缘
接受
ode没有为任何一个提供类型。我相信编译器将
Integer
分配给了这两个。通过预先为这两个问题指定一个类型,问题就解决了。谢谢你的耐心,每天我都在学习思考慢一点但更清晰一点。
import Control.Monad
import Data.Maybe

nfa2 :: String -> Int -> [((Int, Char), [Int])] -> [Int] -> [Int]
nfa2       [] cur     _ acc = guard (cur `elem` acc) >> return cur
nfa2 (c:rest) cur edges acc = do
    state <- fromMaybe mzero $ lookup (cur, c) edges
    nfa2 rest state edges acc

edges =
    [ ((1, 'a'), [2, 3])
    , ((2, 'a'), [2])
    , ((3, 'b'), [3, 4])
    , ((4, 'c'), [5])
    ]

accepting = [2, 5]

main = do
    print $ nfa2 "aaa" 1 edges accepting
    print $ nfa2 "abc" 1 edges accepting
    print $ nfa2 "abb" 1 edges accepting
    print $ nfa2 "aabc" 1 edges accepting
[2]
[5]
[]
[]