Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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 在一词多义中运行一次NonDet效应_Haskell_Non Deterministic_Haskell Polysemy - Fatal编程技术网

Haskell 在一词多义中运行一次NonDet效应

Haskell 在一词多义中运行一次NonDet效应,haskell,non-deterministic,haskell-polysemy,Haskell,Non Deterministic,Haskell Polysemy,我对一词多义相对来说是个新手,我正在努力思考如何正确使用NonDet。具体来说,假设我有这个计算 generate :: Member NonDet r => Sem r Int generate = msum $ fmap pure [0..] computation :: (Member NonDet r, Member (Final IO) r) => Sem r () computation = do n <- generate guard (n == 100

我对一词多义相对来说是个新手,我正在努力思考如何正确使用
NonDet
。具体来说,假设我有这个计算

generate :: Member NonDet r => Sem r Int
generate = msum $ fmap pure [0..]

computation :: (Member NonDet r, Member (Final IO) r) => Sem r ()
computation = do
  n <- generate
  guard (n == 100)
  embedFinal $ print n
这个不能短路。它打印出100,但永远挂起,再次寻找数字100。这是有道理的;毕竟,我并没有告诉它我只想要一个解决方案。让我们试试看

我的第二次尝试 我们要做的就是把名单上的头号人物都扔掉。可以理解,这并没有改变任何事情。Haskell已经没有计算列表,因此丢弃未使用的值不会改变任何内容。与
attempt1
类似,此解决方案在打印100后永远挂起

我的第三次尝试 所以我试着用。不幸的是,这一个没有打印任何内容就退出了。弄清楚为什么需要一点时间,但我有一个理论。文件上说

与runNonDet不同,如果第一个选项成功,则使用将根本不会执行第二个分支

因此,它是贪婪的,基本上不会在成功后倒退。因此,它像这样运行我的计算

computation = do
  n <- generate        -- Ah yes, n = 0. Excellent!
  guard (n == 100)     -- Wait, 0 /= 100! Failure! We can't backtrack, so abort.
  embedFinal $ print n
因此,我们只需将
generate
移动到
computation
的内部,而不是生成一个数字然后稍后再检查它。通过此
计算
尝试3
成功,因为我们可以在不回溯的情况下得到“正确”的答案。在这个小示例中,这是可行的,但对于较大的代码库来说是不可行的。除非有人有一个很好的系统方法来避免回溯,否则我看不到一个好的方法来将这个解决方案推广到大型程序中跨多个文件的计算

另一个非解决方案是使用
IO
作弊

computation :: (Member NonDet r, Member (Final IO) r) => Sem r ()
computation = do
  n <- generate
  guard (n == 100)
  embedFinal $ print n
  embedFinal $ exitSuccess
computation::(成员非集合r,成员(最终IO)r)=>Sem r()
计算=do
N
现在attempt1和attempt2成功了,因为我们只是在成功后强制退出程序。但是,除了令人难以置信的邋遢,这也不能概括。我想在找到100后停止运行当前的计算,而不是整个程序


与其说是
exitSuccess
,不如说是抛出一个可以在解释器中捕捉到的异常。

现在你可能想避开
NonDet
:似乎是这样。幸运的是,亚历克西斯·金(莱克西·兰姆达饰)似乎有一个很有希望的解决办法;也许你可以看看这个?这对我来说很有用。我对使用错误退出作用域所带来的性能影响有点担心,但在可预见的将来它肯定足够了。谢谢你的帮助!
attempt3 :: IO ()
attempt3 = void . runFinal . runNonDetMaybe $ computation
computation = do
  n <- generate        -- Ah yes, n = 0. Excellent!
  guard (n == 100)     -- Wait, 0 /= 100! Failure! We can't backtrack, so abort.
  embedFinal $ print n
computation :: (Member NonDet r, Member (Final IO) r) => Sem r ()
computation = msum $ fmap (\n -> guard (n == 100) >> embedFinal (print n)) [0..]
computation :: (Member NonDet r, Member (Final IO) r) => Sem r ()
computation = do
  n <- generate
  guard (n == 100)
  embedFinal $ print n
  embedFinal $ exitSuccess