我认为这个问题最好用一个例子说明。
包含非确定性函数的类型:
data ND a b = N { runN :: a -> [(b, ND a b)] }
instance Show (ND a b) where
show n = show "<ND>"
ND
的一个例子:
nd :: ND String Int
nd = N $ \a -> case a of
"hello" -> [(length a, nd), (length a + 100, nd)]
"world" -> [(length a + 10, nd)]
_ -> []
备注:请注意nd如何输出元组列表,每个元组包含计算结果,以及新的ND
(实际上与原始元组相同,但现在让我们忽略它。)
现在构建一个从源接收输入并为所有输入运行nd的进程。
错误的Process
:
-- | Please note this is wrong, since only the first result of computation is used
toProcess :: ND a b -> Process a b
toProcess = construct . plan where
plan n = do
a <- await
case runN n a of
[] -> stop
((b,n'):xs) -> yield b >> plan n'
备注:上面的这个过程是错误的,因为只采取了第一个计算结果。理想情况下,该进程应分支到多个并行进程,每个进程产生一个输出b,并使用自己的n'
版本进行递归。最终结果应该是可能结果列表
用例:
ret :: [Int]
ret = run $ source ["hello", "world", "again"] ~> toProcess nd
-- Run with toProcess above:
[5,15]
-- But ideally, should yield a list of possible results:
[[5,15],[105,15]]
答案 0 :(得分:2)
我相信你需要将你的计算嵌入到[]
monad中,这是一种如何对非确定性计算进行建模的自然方法。然后,您将拥有ProcessT []
,PlanT []
等等:
toProcess :: ND a b -> ProcessT [] a b
toProcess = construct . plan where
plan n = do
a <- await
case runN n a of
[] -> stop
xs -> do
(b, n') <- lift xs
yield b
plan n'
ret :: [[Int]]
ret = runT $ source ["hello", "world", "again"] ~> toProcess nd
-- produces: [[5,15],[105,15]]