在这个例子中,我的Haskell定义了绑定运算符有什么问题?

Ana*_*Ana 4 monads haskell ghc ghci

我在这里关注monad变形金刚教程.

在本教程的这一点上,它要求我尝试为EitherIO数据类型实现Monad实例,定义如下:

data EitherIO e a = EitherIO {
    runEitherIO :: IO (Either e a)
}
Run Code Online (Sandbox Code Playgroud)

所以我尝试过:

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
Run Code Online (Sandbox Code Playgroud)

该教程的版本有点不同:

instance Monad (EitherIO e) where
  return  = pure -- the same as EitherIO . return . Right
  x >>= f = EitherIO $ runEitherIO x >>= either (return . Left) (runEitherIO . f)
Run Code Online (Sandbox Code Playgroud)

现在,所有类型都适合,所以我认为我很好,并祝贺自己终于找到了用途join.

事实证明,在教程的下方,我被要求运行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)
Run Code Online (Sandbox Code Playgroud)

使用我的>>=运算符版本,GHCi会在我提供一些输入后挂起.然后,即使在我打断通过后^C,GHCi也会开始奇怪地行动,在我打字的时候挂了一两秒钟.我必须杀死GHCi重启.当我用>>=教程定义替换定义时,一切正常.

我的完整档案在这里.

所以:

  1. 我的定义有什么问题?

  2. 为什么GHCi会进行类型检查,然后表现得像它一样?这是GHCi的错误吗?

chi*_*chi 6

我的猜测是,这是罪魁祸首:

instance Monad (EitherIO e) where
  return  = EitherIO . return . Right
  x >>= f = join $ fmap f x
Run Code Online (Sandbox Code Playgroud)

但是,join定义为:

join x = x >>= id
Run Code Online (Sandbox Code Playgroud)

但是,以这种方式join>>=以相互递归的方式定义,导致非终止.

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

f, g :: Int -> Int
f x = g x
g x = f x
Run Code Online (Sandbox Code Playgroud)

底线:您应提供>>=不涉及的定义join.

  • @Ana没有,AFAIK.拇指规则是你不应该使用任何需要`Monad(EitherIO e)`的函数来定义实例本身.(这种循环定义在某些情况下可能仍然会导致终止,但通常情况并非如此.) (2认同)

ips*_*sec 5

joinin Control.Monad定义如下:

join              :: (Monad m) => m (m a) -> m a
join x            =  x >>= id
Run Code Online (Sandbox Code Playgroud)

你看,这join是根据的定义>>=.所以简短的回答是,你的定义>>=进入无限循环(即不终止),因为它使用join,反过来>>=再次使用.

如果你仔细想想,你可以使用这个定义>>=每一个Monad.因此它不可能工作,因为它根本不使用该类型的内部结构.

至于为什么没有检测到ghc这个,这是一个无限循环,但不是类型错误.Haskell的类型系统不足以检测这种循环.