Haskell:使用do符号并返回的函数,即Integer值

时间:2013-06-18 18:57:56

标签: haskell monads do-notation

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

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

我必须为此写自己的monad吗?有没有解决方案不写新的monad?


修改

所以我可以编写使用main的{​​{1}}函数,我认为这是唯一的解决方案:

fun

以上代码可以使用。

2 个答案:

答案 0 :(得分:1)

你的功能类型应该是

fun :: IO (Integer, Integer)

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

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

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

虽然有些方法可以使用不安全的功能从IO中解决问题,但在您确切知道自己在做什么之前不建议这样做。

答案 1 :(得分:1)

如上所述,您需要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