您可能不想使用main 来返回内容,因为它是您程序的入口点。相反,您可以编写一个函数
getInt :: IO Int
getInt = do
input <- getLine
return (read input) -- Don't have to specify Int here, GHC can figure it out from the type signature
但是,您的函数setBrick 可能具有Int -> Int -> Int -> [[Int]] -> [[Int]] 类型,不能直接使用getInt。这是设计使然,Haskell 的类型系统迫使您将 IO 操作与纯函数分开处理(一旦您习惯了它,它就是推理代码的绝佳工具)。相反,您可以执行类似的操作
promptInt :: IO Int
promptInt = do
putStrLn "Please input a number."
getInt
usrSetBrick :: [[Int]] -> IO [[Int]]
usrSetBrick xs = do
a <- promptInt
b <- promptInt
c <- promptInt
return $ setBrick a b c xs
Int 和 IO Int 在 Haskell 中的类型不一样,不能互换使用。这也适用于[Int]、Maybe Int 和Either String Int 之类的类型,它们都与Int 不同。由于main 是一个IO 函数,它不返回Int,而是返回IO Int。事实上,return 根本不是 Haskell 中的特殊构造,它只是一个普通函数,恰好将值包装在 Monad 中。在这种情况下,使用的Monad 是IO,因此return (read inputjar :: Int) 的类型为IO Int。
为了扩展下面@Zeta 的评论,Haskell 的return 并不特别,更重要的是不会提前退出函数。下面的代码将证明这一点:
doSomething :: IO Int
doSomething = do
return "Test" -- Wouldn't type-check if this exited early
return 123 -- Would type check, but is ignored
putStrLn "You'll see this line printed"
return () -- Doesn't affect anything
x <- getLine -- Still happens
return 5678
putStrLn "Your input is meaningless! Here's a 0"
return ([1, 2], "hello", "world")
return 0 -- This is the actual return value
所有这些额外的回报在 Haskell 中没有任何作用(至少在 IO monad 中)。所发生的只是一个值被包装在构造函数中,并与该函数中的其余语句链接在一起。 Haskell 社区中甚至有些人认为return 既不必要又令人困惑。从技术上讲,return 等同于pure 对应于Applicatives,并且所有Monads 也是Applicatives,所以它并没有真正为我们提供任何东西。在遥远的未来的某个时刻,return 函数可能会完全消失,被pure 完全取代。同样,这些函数都不是 Haskell 语法的一部分,它们在核心库中被定义为普通的普通函数。