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

如何在Haskell中使用不同类型monad的值,haskell,types,monads,Haskell,Types,Monads,老实说,我觉得这一定是个骗局,但我找不到 假设我有以下代码,只需从用户处读取一个double并将其回显: import qualified Control.Monad.E除外 导入文本。读取(readMaybe) 数据错误=解析错误字符串 |默认字符串派生(显示) 类型ThrowsError=任一错误 main=do putStrLn“输入您的号码:” val ThrowsError双精度 parseString val=可能(例如,throwError$ParseError val)返回 (r

老实说,我觉得这一定是个骗局,但我找不到

假设我有以下代码,只需从用户处读取一个double并将其回显:

import qualified Control.Monad.E除外
导入文本。读取(readMaybe)
数据错误=解析错误字符串
|默认字符串派生(显示)
类型ThrowsError=任一错误
main=do
putStrLn“输入您的号码:”
val ThrowsError双精度
parseString val=可能(例如,throwError$ParseError val)返回
(readMaybe val::Maybe Double)
getDouble::ThrowsErrorDouble
getDouble=getLine>>=parseString
这在两个地方中断:

  • main
    中,
    putStrLn
    是类型
    IO-Double
    ,但
    getDouble
    是类型
    ThrowsError-Double

  • getDouble
    中,
    getLine
    是类型
    iodouble
    ,但
    parseString
    返回
    iodouble

  • 本质上,我希望能够从
    IO
    monad中提取值,对其进行计算,然后将其放回相应的monad中。然而,bind函数似乎期望输入和输出具有相同的monad类型,因此我想要做的事情不起作用


    有什么办法吗?

    你不需要任何变压器
    parseString
    是一个纯函数,因此要将其应用于一元操作,您可以使用
    fmap
    (也称
    ()
    ),而不是像您使用的那样使用
    (>>=)

    getDouble :: IO (ThrowsError Double)
    getDouble = parseString <$> getLine
    
    getDouble::IO(ThrowsError Double) getDouble=parseString getLine
    您可以使用
    (>>=)
    如果
    parseString
    返回了
    IO something

    问题是,您不能只打开任意单子。因此,您要做的是将monad与monad转换器堆叠在一起。您需要类似于
    键入ThrowsError m=ExceptT Error m
    getDouble::ThrowsError IO Double
    的内容,并将
    提升
    放在适当的位置。情况总是相反:使用monad,您无法自由提取值。但是您可以将您的操作提升到monad的上下文中。提升是函子操作。啊,只要
    fmap
    在Monad中应用即可。非常感谢。