基础的Haskell IO(IO String -> Int)是什么?

3

我是一个初学的 Haskell 程序员。我想用一个简单的命令行程序来表示披萨公式,根据输入的人数返回适当的披萨数量。我知道我需要将我的输入 (IO String) 转换为 Int 类型,然后使用 show 将结果转换为字符串。我该如何实现 IO String -> Int 的转换?或者我的做法完全错误?

import System.Environment
import System.IO

pizzas :: Integral a => a -> a
pizzas x = div (x * 3) 8

main = do
    putStrLn "How many people are you going to feed?"
    arg <- getLine
    -- arg needs to IO String -> Int
    -- apply pizzas function
    -- Int -> String
    putStrLn "You will need to order " ++ string ++ " pizzas."

4
看起来你已经收集到了一些好的答案,为你提供了很好的提示。所以就一般而言:每当你开始思考 IO foo -> bar 时,你应该紧张地眯起眼睛。一旦进入 IO,你无法 (咳咳) 退出,而这是件好事。 - Daniel Wagner
我不确定我理解了... 我认为 Haskell 的工作方式是: 输入 -> [纯函数魔法] -> 输出,在这里安全地粘合纯代码和不纯的数据是整个重点。或者说,我可以用更符合习惯的方式来表达这个问题吗? - Daniel
1
@Daniel 是的,那是正确的。但是...你不能真正从 IO a 转换为 a,除非在一个实际返回类型 IO a 的函数中;相反,你要做的是编写一个函数 f x = y,然后在 main 中,你可以像这样做:x <- readX; putStrLn (f x)。在这里,xIO 中“提取”出来并传递给你的纯程序 (f),所以你的其余代码可以是纯的。但是你只能在可以进行 IO 的函数内部做这种事情;通常情况下,你不能将 IO a 转换为 a - amalloy
1
@Daniel,你可以使用像“输入->输出”这样的类型来编写计算程序;但是你需要将该计算与某个小部件连接起来,该小部件实际上与世界进行交互并生成类型为“输入”的值,然后以一种显示类型为“输出”的值的方式与世界进行交互。 IO类型的集合可以做到这一点- GHC有一个特殊符号main,它启动了这些操作。但是你无法从IO中“退出”。IO foo -> IO bar没问题;IO foo -> bar,其中bar中没有IO,则没有太多有趣的实现。 - Daniel Wagner
是的,看起来我需要学习很多关于绑定封装数据的知识。似乎Haskell让难事情(重构代码、单元测试等)变得容易,而简单的事情(IO、打印多行、格式化字符串、库管理等)变得棘手。 - Daniel
你提到的简单事情在 Haskell 中非常容易。 - Erik Kaplun
1个回答

4
使用read函数可以将字符串转换为适当的类型(如果可能的话)。
而使用show函数可以将整数转换为它的字符串表示形式。
arg <- getLine
let num = pizzas (read arg)
putStrLn $ "You will need to order " ++ (show num) ++ " pizzas."

或者这样做:
arg <- readLn :: IO Int
let num = pizzas arg
putStrLn $ "You will need to order " ++ (show num) ++ " pizzas."

4
这个答案在技术上是正确的,但需要理解的是,当你使用 arg <- getLine 时,arg 的类型为 String,因为这个绑定操作将值从 IO 容器中“提取”出来。然后,你只需要使用 read arg 并将其作为参数发送给 pizzas 函数,在此时 Haskell 将会推断出正确的类型。 - Yawar
我收到了两个解决方案都显示“在‘=’输入上的解析错误”的错误:~/ - Daniel
编译成功了!感谢您提供的解决方案和解释。 - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接