【问题标题】:Haskell: Function using do notation and returning i.e. Integer valueHaskell:使用 do 表示法并返回即整数值的函数
【发布时间】:2013-06-18 18:57:56
【问题描述】:

我想编写一个函数,它使用getLine 读取一些数据并返回,即一个元组 (Integer, Integer) 但使用 do-notation。像这样的东西(当然它不起作用):

fun :: (Integer, Integer)
fun = do
    a <- read (getLine::Integer)
    b <- read (getLine::Integer)
    return (a, b)

我必须为此编写自己的 monad 吗?有什么办法可以不写一个新的 monad 吗?


编辑

所以我可以编写使用funmain 函数,我认为这是唯一的解决方案:

main :: IO ()
main = do
    tuple <- fun
    putStrLn (show tuple)

fun :: IO (Integer, Integer)
fun = do
    a1 <- getLine
    b1 <- getLine
    let a = read (a1)
        b = read (b1)
    return (a, b)

以上代码有效。

【问题讨论】:

  • 那不可能,fun的类型必须是IO(Int, Int),不能离开IO Monad。
  • 请注意,return 的含义与您在程序语言中可能习惯的完全不同。你所拥有的不是函数。在函数中,“返回”的结果就是= 右侧的表达式。相比之下,return 总是将一个值注入某个 monad(在 GHCi 中输入 :t return 时可以很清楚地看到它),在这种情况下是 IO monad。

标签: haskell monads do-notation


【解决方案1】:

你的函数类型应该是

fun :: IO (Integer, Integer)

正如@kaan 所提到的,您不应该尝试从 monad 中获取 mondic 值(带有副作用),因为这会破坏引用透明度。运行fun 应该总是返回相同的值,无论它运行多少次,如果我们使用你的类型,这不会发生。但是,如果类型是IO (Integer, Integer),那么每次使用该函数时它都会返回相同的操作,并且运行此操作实际上会执行从控制台读取值的副作用。

回到使用你的功能。您可以在另一个 IO monad 中执行此操作,例如

main = do
  (a,b) <- fun
  print a
  print b

虽然有一些方法可以使用不安全的函数从IO 中取出东西,但在您确切知道自己在做什么之前不建议这样做。

【讨论】:

    【解决方案2】:

    如前所述,您需要将 fun 类型指定为 IO (Integer, Integer) 而不是 (Integer, Integer)。然而,一旦你屈服于这种命运,有很多方法可以剥去这只猫的皮。这里有一些方法可以激发您的想象力。

    fun = do
        a <- getLine
        b <- getLine
        return (read a, read b)
    
    -- import Control.Applicative for (<$>)
    -- can also spell (<$>) as fmap, liftA, liftM, and others
    fun = do
        a <- read <$> getLine
        b <- read <$> getLine
        return (a, b)
    
    fun = do
        a <- readLn
        b <- readLn
        return (a, b)
    
    fun = liftM2 (,) readLn readLn
    
    -- different type!
    -- use in main like this:
    -- main = do
    --        [a, b] <- fun
    --        foo
    -- import Control.Monad for replicateM
    fun :: IO [Integer]
    fun = replicateM 2 readLn
    

    【讨论】:

      猜你喜欢
      • 2019-12-19
      • 2023-03-09
      • 1970-01-01
      • 2021-03-15
      • 2016-09-04
      • 1970-01-01
      • 2021-07-14
      • 1970-01-01
      相关资源
      最近更新 更多