gpt4 book ai didi

haskell - 与 Netwire 一起使用时对 ArrowLoop 的误解

转载 作者:行者123 更新时间:2023-12-01 03:48:19 27 4
gpt4 key购买 nike

跟随 this post 中优秀答案的引领,我正在尝试获取 ArrowLoop 的工作示例不使用箭头符号。在我完全理解箭头在引擎盖下的工作原理之前,我对使用箭头符号感到不舒服。话虽如此,我已经构建了一个基于我对 Arrows 的(有限)理解的小程序应该可以工作。然而,它最终以可怕的 <<loop>> 结束。异常(exception):

module Main where

import Control.Wire
import FRP.Netwire

farr :: SimpleWire (Int, Float) (String, Float)
farr = let
fn :: Int -> Float -> ((String, Float), SimpleWire (Int, Float) (String, Float))
fn i f = (("f+i: " ++ (show (fromIntegral i + f)), f + 0.1), loopFn)

loopFn :: SimpleWire (Int, Float) (String, Float)
loopFn = mkSFN $ \(i, f) -> fn i f
in
mkSFN $ \(i, _) -> fn i 0.0

main :: IO ()
main = do
let sess = clockSession_ :: Session IO (Timed NominalDiffTime ())
(ts, sess2) <- stepSession sess

let wire = loop farr
(Right s, wire2) = runIdentity $ stepWire wire ts (Right 0)

putStrLn ("s: " ++ s)

(ts2, _) <- stepSession sess2
let (Right s2, _) = runIdentity $ stepWire wire2 ts (Right 1)

putStrLn ("s2: " ++ s2)

我的直觉告诉我, <<loop>>当您不向循环提供初始值时,通常会出现异常。我不是用包含 fn i 0.0 的行完成的吗? ?输出不一致:
$ ./test
s: f+i: 0.0
test.exe: <<loop>>

有谁知道我做错了什么?

最佳答案

主要的混淆点似乎是 ArrowLoop 之间的积分关系。和 mfix .对于初学者,fix是一个函数,finds the fixed point给定函数的:

fix :: (a -> a) -> a
fix f = let x = f x in x
mfix是这个函数的 monadic 扩展,不出所料,它的类型签名是:
mfix :: (a -> m a) -> m a

那么这与 ArrowLoop有什么关系? ?嗯, ArrowLoop Netwire 运行的实例 mfix在传递的电线的第二个参数上。换句话说,考虑 loop 的类型签名:
loop :: a (b, d) (c, d) -> a b c

在Netwire中, ArrowLoop的实例是:
instance MonadFix m => ArrowLoop (Wire s e m)

这意味着 loop与电线一起使用时的函数类型是:
loop :: MonadFix m => Wire s e m (b, d) (c, d) -> Wire s e m b c

loop不采用 d 类型的初始参数,这意味着无法通过线路初始化任何类型的常规“循环”。从中获取值的唯一方法是继续应用输出作为输入,直到找到终止条件,这类似于 fix作品。作为参数传递给 loop 的线路实际上从来没有超过一次,因为 stepWire用不同的输入一遍又一遍地应用于同一条电线。只有当导线实际产生一个固定值时,函数才会步进并产生另一条导线(其行为方式与第一条相同)。

为了完整起见,这里是我原始直觉的代码 loop应该可以工作,我将其命名为 semiLoop :
semiLoop :: (Monad m, Monoid s, Monoid e) => c -> Wire s e m (a, c) (b, c) -> Wire s e m a b
semiLoop initialValue loopWire = let
runLoop :: (Monad m, Monoid s, Monoid e) =>
Wire s e m (a, c) (b, c) -> s -> a -> c -> m (Either e b, Wire s e m a b)
runLoop wire ts ipt x = do
(result, nextWire) <- stepWire wire ts (Right (ipt, x))
case result of
Left i -> return (Left i, mkEmpty)
Right (value, nextX) ->
return (Right value, mkGen $ \ts' ipt' -> runLoop nextWire ts' ipt' nextX)
in
mkGen $ \ts input -> runLoop loopWire ts input initialValue

编辑

wonderful answer由 Petr 提供, delay组合器对于防止 loop 至关重要组合子发散。 delay简单地在使用 mfix 中的下一个值的懒惰之间创建一个单值缓冲区。上述循环的一部分。 semiLoop的相同定义因此,以上是:
semiLoop :: (MonadFix m, Monoid s, Monoid e) =>
c -> Wire s e m (a, c) (b, c) -> Wire s e m a b
semiLoop initialValue loopWire = loop $ second (delay initialValue) >>> loopWire

关于haskell - 与 Netwire 一起使用时对 ArrowLoop 的误解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25131107/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com