如何在 Haskell 中使用来自不同类型 monad 的值

Gus*_*ust 2 monads haskell types

老实说,我觉得这必须有一个傻瓜的地方,但我找不到 甚至 搜索

假设我有以下代码来简单地从用户那里读取一个 double 并将其回显:

import qualified Control.Monad.Except as E
import Text.Read(readMaybe) 

data Error = ParseError String
             | Default String deriving (Show)

type ThrowsError = Either Error 

main = do
  putStrLn "Enter your number: "
  val <- getDouble
  print val

parseString :: String -> ThrowsError Double
parseString val = maybe (E.throwError $ ParseError val) return 
                        (readMaybe val :: Maybe Double)

getDouble :: ThrowsError Double
getDouble = getLine >>= parseString
Run Code Online (Sandbox Code Playgroud)

这在两个地方中断:

  1. main,putStrLn是类型IO Double但是getDouble是类型ThrowsError Double

  2. getDouble,getLine是类型IO DoubleparseString返回IO Double

本质上,我希望能够从IOmonad 中提取值,对其进行计算,然后将其放回适当的 monad 中。但是,绑定函数似乎期望输入和输出具有相同的 monad 类型,所以我想要做的不起作用。

有什么办法呢?

luq*_*qui 9

你不需要任何变压器。 parseString是一个纯函数,因此要将其应用于您使用的 monadic 操作fmap(又名(<$>)),而不是(>>=)像您那样。

getDouble :: IO (ThrowsError Double)
getDouble = parseString <$> getLine
Run Code Online (Sandbox Code Playgroud)

您将使用(>>=)ifparseString返回一个IO something.