Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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 当与Netwire一起使用时,会出现循环错误_Haskell_Frp_Arrows_Netwire - Fatal编程技术网

Haskell 当与Netwire一起使用时,会出现循环错误

Haskell 当与Netwire一起使用时,会出现循环错误,haskell,frp,arrows,netwire,Haskell,Frp,Arrows,Netwire,在中的优秀答案之后,我试图获得一个不使用箭头符号的ArrowLoop工作示例。在我完全理解箭头在引擎盖下的工作原理之前,我不喜欢使用箭头符号。也就是说,基于我对箭头的(有限的)理解,我已经构建了一个小程序。但是,它最终会以可怕的异常终止: module Main where import Control.Wire import FRP.Netwire farr :: SimpleWire (Int, Float) (String, Float) farr = let fn :: Int

在中的优秀答案之后,我试图获得一个不使用箭头符号的
ArrowLoop
工作示例。在我完全理解箭头在引擎盖下的工作原理之前,我不喜欢使用箭头符号。也就是说,基于我对箭头的(有限的)理解,我已经构建了一个小程序。但是,它最终会以可怕的
异常终止:

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)

有人知道我做错了什么吗?

主要的混淆点似乎是
ArrowLoop
mfix
之间的整体关系。对于未初始化的用户,
fix
是一个给定函数的函数:

fix :: (a -> a) -> a
fix f = let x = f x in x
mfix
是此函数的一元扩展,其类型签名为,毫不奇怪:

mfix :: (a -> m a) -> m a
那么这与
箭头循环
有什么关系呢?好的,Netwire的
ArrowLoop
实例在传递的wire的第二个参数上运行
mfix
。换一种方式,考虑<代码>循环> <代码>的类型签名:

loop :: a (b, d) (c, d) -> a b c
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
在Netwire中,
ArrowLoop
的实例是:

instance MonadFix m => ArrowLoop (Wire s e m)
这意味着与导线一起使用时,
回路
功能的类型为:

loop :: MonadFix m => Wire s e m (b, d) (c, d) -> Wire s e m b c
由于
loop
不接受类型为
d
的初始参数,这意味着无法初始化导线上任何类型的常规“循环”。从中获取值的唯一方法是继续应用输出作为输入,直到找到终止条件,这类似于
fix
的工作方式。作为参数传递给
loop
的连线实际上从未超过一次,因为
stepWire
使用不同的输入反复应用于同一连线。只有当导线实际生成固定值时,功能才会单步执行并生成另一条导线(其行为方式与第一条导线相同)

为了完整起见,下面是我最初直觉的代码,我把它命名为
semiLoop

loop :: a (b, d) (c, d) -> a b c
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

GHCs是告诉您它已检测到评估循环的一种方式;一个表达式,在GHCs评估过程中,它返回到同一个thunk。对,我想再解释一下为什么会发生这种情况,因为我不希望它发生。