Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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定义有什么问题?_Haskell_Monads_Ghc_Ghci - Fatal编程技术网

在本例中,绑定操作符的Haskell定义有什么问题?

在本例中,绑定操作符的Haskell定义有什么问题?,haskell,monads,ghc,ghci,Haskell,Monads,Ghc,Ghci,我正在学习蒙纳德变形金刚教程 ,它要求我尝试为EitherIO数据类型实现Monad实例,定义为: data EitherIO e a = EitherIO { runEitherIO :: IO (Either e a) } join x = x >>= id 所以我试着: instance Functor (EitherIO e) where fmap f = EitherIO . fmap (fmap f) . runEitherIO instance Mon

我正在学习蒙纳德变形金刚教程

,它要求我尝试为
EitherIO
数据类型实现Monad实例,定义为:

data EitherIO e a = EitherIO {
    runEitherIO :: IO (Either e a)
}
join x = x >>= id
所以我试着:

instance Functor (EitherIO e) where
  fmap f = EitherIO . fmap (fmap f) . runEitherIO

instance Monad (EitherIO e) where
  return  = EitherIO . return . Right
  x >>= f = join $ fmap f x
本教程的版本有点不同:

instance Monad (EitherIO e) where
  return  = pure -- the same as EitherIO . return . Right
  x >>= f = EitherIO $ runEitherIO x >>= either (return . Left) (runEitherIO . f)
现在,所有类型都适合,所以我认为我很好,并祝贺自己终于找到了一个使用

结果,我被要求运行
runEitherIO getToken
,运行以下命令:

liftEither x = EitherIO (return x)
liftIO x = EitherIO (fmap Right x)

getToken = do
  liftIO (T.putStrLn "Enter email address:")
  input <- liftIO T.getLine
  liftEither (getDomain input)
liftEither x=EitherIO(返回x)
liftIO x=EitherIO(fmap右x)
getToken=do
liftIO(T.putStrLn“输入电子邮件地址:”)
输入>=
运算符,在我提供一些输入后,GHCi将挂起。即使在我通过
^C
中断之后,GHCi也会开始表现出奇怪的行为,在我打字时会挂上一两秒钟。我必须杀了GHCi才能重新开始。当我用教程定义替换
>=
定义时,一切正常

我的完整档案是

因此:

  • 我的定义有什么问题

  • 为什么GHCi会进行打字检查,然后表现得像它那样?这是一个GHCi错误吗


  • 我猜这就是罪魁祸首:

    instance Monad (EitherIO e) where
      return  = EitherIO . return . Right
      x >>= f = join $ fmap f x
    
    但是,
    join
    定义为:

    data EitherIO e a = EitherIO {
        runEitherIO :: IO (Either e a)
    }
    
    join x = x >>= id
    
    但是,通过这种方式,
    join
    >=
    以一种相互递归的方式定义,从而导致不终止

    请注意,此类型将进行检查,如下所示:

    f, g :: Int -> Int
    f x = g x
    g x = f x
    
    底线:您应该为
    >=
    提供一个定义,该定义不涉及
    控件中的
    连接

    join              :: (Monad m) => m (m a) -> m a
    join x            =  x >>= id
    
    你看,
    join
    是根据
    >=
    定义的。因此,简单的回答是,您对
    >=
    的定义进入了一个无休止的循环(即不终止),因为它使用了
    连接
    ,而连接又使用了
    >=

    如果您仔细想想,您可以对每个
    单子
    使用
    >=
    的定义。所以它不可能工作,因为它根本没有使用类型的内部结构


    至于为什么ghc没有检测到这一点,这是一个无休止的循环,但不是类型错误。Haskell的类型系统不足以检测此类循环。

    您实际上无法定义
    join
    ,它不是该类的方法。有计划将其纳入AMP提案中,但它与新类型派生的角色系统的交互作用不好。(基本上,这会使单子堆栈的新类型派生变得不可能。)我明白了。。。我想没有一个可用的函数列表被标记为禁止在Monad定义中使用?@Ana没有,AFAIK。经验法则是,您不应该使用任何需要
    Monad(EitherIO e)
    来定义实例本身的函数。(在某些情况下,此循环定义仍可能导致终止,但通常情况下并非如此。)