Using id inside do notation

use*_*035 0 monads haskell

I am watching a Haskell online course, Reader monad chapter. The instructor gives the following example: this function takes a list and returns Nothing if it's empty or (Just head) otherwise.

safeHead = do
  -- argument is implicit here
  b <- null
  if b then
    return Nothing
  else do
    h <- head
    return $ Just h

safeHead' = do
  e <- id -- the error
  if (null e)
    then Nothing
    else return $ Just (head e)
Run Code Online (Sandbox Code Playgroud)

第二个函数使用显式获取列表e <- id。但是,不幸的是,它对我不起作用。ghci给出了一个错误:

• Couldn't match expected type ‘Maybe [a]’
              with actual type ‘a0 -> a0’
 • Probable cause: ‘id’ is applied to too few arguments
    In a stmt of a 'do' block: e <- id
    In the expression:
      do e <- id
         if (null e) then Nothing else return $ Just (head e)
Run Code Online (Sandbox Code Playgroud)

该示例可能是3年前创建课程时由作者测试的(或者从一开始就是错误的)。

我怀疑是null采用了包装的值,而id没有:

Prelude> :t null
null :: Foldable t => t a -> Bool
Prelude> :t id
id :: a -> a
Run Code Online (Sandbox Code Playgroud)

怎么了,怎么解决?

K. *_*uhr 7

实际上,您只是忘记了一个return。以下工作正常:

safeHead' = do
  e <- id
  if (null e)
    then return Nothing         -- need return here
    else return $ Just (head e)
Run Code Online (Sandbox Code Playgroud)

或者您可以将其return排除在外:

safeHead' = do
  e <- id
  return $ if (null e)
    then Nothing
    else Just (head e)
Run Code Online (Sandbox Code Playgroud)