2016-11-22 5 views
0

私は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 

開始状態は常に即ちcurrent = 1第一の状態です。このよう"aaa"や​​など

文字列は"abb"または"aabc"ながら、承認または拒否されています。

書き換えでの私の試み使用ハスケル:

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

私は入力文字列の末尾に最後の状態を表す整数のリストを返すようにしたいし、その後filterこれらの受理状態に対してとにanyを使用最終的にTrueまたはFalseを取得してください。

これはおそらく、これを行うためのHaskellの方法ではないこと、そしておそらくより良いwholemeal解決策があることを認識しています。しかし、初心者としては、私はモンダディックメカニズムと、おそらくこの問題の再帰的な性質に苦しんでいます。

リストの理解ではなく、doの表記を使用して正しい方向に向けるようにしてください。

+1

あなたは、運動へのリンクを追加してもらえますか? – Zeta

+0

@Zeta [プログラミング言語](https://www.udacity.com/course/programming-languages--cs262) – potong

答えて

2

まずタイプを考えてみましょう。

type State = Int 
type Map k v = [(k,v)] 

nfsmSim :: String -> State -> Map (Int, Char) [State] -> [State] -> Bool 
nfsmSim string current edges accepting = … 

私たちは、空の文字列の場合のパターンマッチングを使用することができます:あなたのPythonの関数は次の型、多かれ少なかれあり

nfsmSim :: String -> State -> Map (Int, Char) [State] -> [State] -> Bool 
nfsmSim "" current _ accepting = current `elem` accepting 

空でない場合については、私たちは同じことを行いますあなたのPythonコードとして:

nfsmSim (x:xs) current edges accepting = 
    let rest = xs 
     states = [s | (k,v) <- edges, k == (current,x), s <- v] 
    in or [nfsmSim rest state edges accepting | state <- states] 

しかし、これは本当に扱いが簡単ではありません。代わりに、私たちは高階関数としてnfsmSimを書いて、引数の順序を変更してみましょう:

nfsmSim :: (State -> Char -> [State]) 
     -> (State -> Bool) 
     -> String 
     -> State 
     -> Bool 

は今、代わりにエッジのリストで、我々はのための状態の(可能な空の)リストを返す関数を提供する必要があります与えられた状態と文字と受け入れ状態のリストの代わりに、我々はそれらの状態でTrueを返す関数を提供する。空の文字列の場合については

、あまりにも多くの変更:

nfsmSim advance accept "" current = accept current 

我々は単に私たちの現在の状態が許容できるかどうかを確認するために私たちのState -> Boolを使用しています。それは一種の不格好に沿ってすべての引数を運ぶためだと

nfsmSim advance accept (x:xs) current = 
    any (nfsmSim advance accept xs) (advance current x) 

注:

しかし、今、私たちのStatenfsmSimの最後のパラメータであることを、私たちはあなたのanyアプローチを使用するようにカリー化を使用することができます。高階関数ことを示している

nfsmSimAccept string current edges accepting = 
    let accept c = c `elem` accepting 
     advance c x = [s | (k,v) <- edges, k == (c,x), s <- v] 
    in nfsmSim advance accept string current 
ところで

nfsmSim :: (a -> b -> [a]) -> (a -> Bool) -> [b] -> a -> Bool 
nfsmSim advance accept string current = go string current 
    where 
    go []  c = accept c 
    go (x:xs) c = any (go xs) (advance c x) 

、あなたはまだ最後の変種で「エッジ」と「受諾」を使用することができ、

:あなたは通常、そのために労働者を記述しますより柔軟性があります。

当社は、ステートマシンを表現するためにHaskellのData.SetとData.Mapライブラリを使用することができます。

+0

あなたのソリューションをありがとうございます。あなたは私の低能力でちょうど答えを投げてきました。私はあなたのデータアプローチから多くを学んできました。私はあなたの最初のソリューションをコピーし、私のhaskell replでそれを実行したときに、私は 'Integer'と 'Int'をマッチさせることができませんでした。期待されるタイプ:[状態];実際のタイプ:[整数] '。私はIntをどこでもIntegerに置き換えてコンパイルしました。理由は何ですか? – potong

+0

@potongあなたはどこかで '整数 'を使いましたか? – Zeta

+0

解決策をそのままコピーしました。ハスケルのバージョン(7.6.3)には、おそらく関係がありますか?私が 'b'を' Char'に置き換えるまで、最終的な解決策にも反対しました。タイプシステムは、私の泥だらけの思考を助け、明確にするためにそこにあることを理解していますが、時にはそのエラーメッセージに少し鈍いように見えることもあります。私はメッセージをより深く研究しなければならないと思うか、もっと冗長な説明を与えることができるスイッチがありますか? – potong

2

は、ここに私はHaskellっぽい方法です。

import qualified Data.Map as M 
import qualified Data.Set as S 

のは、私たちの状態マシンにはいくつかのデータ型を定義してみましょう:

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) [email protected](edges, _) currentState = 
    case M.lookup (currentState, ch) edges of 
     Nothing -> False 
     Just nextStates -> 
      or $ S.map (runMachine rest machine) nextStates 
私たちは以下のようなものを、マシンを定義

type State = Int 
type Edge = (State, Char) 
type Machine = (M.Map Edge (S.Set State), S.Set State) 

この関数はを返しますでは、モナドや表記を使用する大きな理由はありません。しかし、Boolの代わりにMaybe()タイプを使用すると、Just()Trueを表し、NothingFalseを表す場合、そのような解決策が可能です。

+0

'Set'は過剰です。 「終了」状態をソートされたセットにする必要はありません。 – Zeta

+0

あなたのソリューションに感謝します。私はハスケル理解のレベルが低いので、あなたが紹介するコンセプトの多くがうまくいっていれば、より意味のあるものになります。 – potong

4

まず、私が知っているように、「非有限状態機械」のようなものはありません。あなたが書いたことから判断すると、それは「非決定的有限オートマトン(NFA)」に関することです。

第1変種。

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 

出力は次のようになります。

True 
True 
False 
False 

第二の変形例:

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] 
[] 
[] 
+0

私のちょっとした疑問を訂正してくれてありがとう!私はタイトルを編集しました。 'ちょうど州< - ルックアップ(cur、c)edges'はモナドですか?しかし、 'do'も' return'もありませんか? – potong

+0

いいえ、Haskell 2010の構文 "Patter guard"(https://wiki.haskell.org/Pattern_guard) – freestyle

関連する問題