我在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"
或"abc"
或"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)]
等字符串。
我尝试使用Haskell重写:
filter
我想返回一个整数列表,它表示输入字符串末尾的最后一个状态,然后any
表示接受状态,并使用True
得到最终False
}或wholemeal
。
我意识到这可能不是Haskell的做法,并且可能有更好的do
解决方案。然而作为一个初学者,我正在努力解决mondadic机制,很可能是这个问题的递归性质。
请指出正确的方向,可能使用 srand((unsigned int) time(NULL));
algorytm a;
fstream wynik;
wynik.open("result.txt",ios::out | ios::app);
for(int i=0; i<how_test; i++){ //how many tests
write(how_n); //how many n in my file, and create file
a.read() //read from file (n, and weight / val)
time_start();
a.sort(); //I sort it
a.intoKnapsack(0, 0.0, 0.0); //my function above, so I give here a 3x to do it properly over and over in loop
get_time(); //stop time
measurement+=get_time();
result<<get_time()<<" s."<<endl; //just for
}
符号而非列表理解。
答案 0 :(得分:4)
首先,据我所知,没有“非有限状态机”这样的东西。从你写的内容来看,我意识到它是关于“非确定性有限自动机(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
输出将是:
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]
[]
[]
答案 1 :(得分:2)
让我们首先考虑类型。您的Python函数具有以下类型,或多或少:
type State = Int
type Map k v = [(k,v)]
nfsmSim :: String -> State -> Map (Int, Char) [State] -> [State] -> Bool
nfsmSim string current edges accepting = …
我们可以使用模式匹配来处理空字符串:
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
来检查我们当前的状态是否可以接受。
但是,现在我们的State
是nfsmSim
的最后一个参数,我们可以使用currying来使用您的any
方法:
nfsmSim advance accept (x:xs) current =
any (nfsmSim advance accept xs) (advance current x)
请注意,随身携带所有参数都很笨拙。你通常会为此写一个工人:
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)
顺便说一句,您仍然可以使用“edge”和“接受”最后一个变体
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
表明高阶函数更灵活。
答案 2 :(得分:2)
这是我的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-notation。但是,如果我们使用Maybe ()
类型代替Bool
,其中Just ()
代表True
而Nothing
代表False
,则可以使用此解决方案。