Haskell输入返回元组
我想知道IO()函数能否返回元组,因为我想从这个函数中获取元组作为另一个函数的输入Haskell输入返回元组,haskell,io,interactive,Haskell,Io,Interactive,我想知道IO()函数能否返回元组,因为我想从这个函数中获取元组作为另一个函数的输入 investinput :: IO()->([Char], Int) investinput = do putStrLn "Enter Username : " username <- getLine putStrLn "Enter Invest Amount : " tempamount <- getLine let amount = show tempamount retur
investinput :: IO()->([Char], Int)
investinput = do
putStrLn "Enter Username : "
username <- getLine
putStrLn "Enter Invest Amount : "
tempamount <- getLine
let amount = show tempamount
return (username, amount)
investinput::IO()->([Char],Int)
输入=do
putStrLn“输入用户名:”
用户名是的,你就快到了,但我想你想要签名:
investinput :: IO ([Char], Int)
。。。然后通过调用函数,您可以执行以下操作:
main = do
(username, amount) <- investinput
....
main=do
(username,amount)生成元组的IO函数的类型为IO(a,b)
,在这种情况下:
investinput :: IO ([Char], Int)
签名为IO()->([Char],Int)
意味着函数接受类型为IO()
的参数,并从中生成一个元组,这不是您想要的
通常情况下,IO函数(或其他monad中的函数)可以返回的类型没有限制,您可以随意选择类型。Haskell中的IO与您习惯的语言中的IO不同。Haskell中的所有函数都必须是纯函数:也就是说,如果使用参数x
调用函数f
,则调用一次、两次或一百次之间必须没有区别。不过,考虑一下这对IO意味着什么。简单地说,getLine
应该具有类型getLine::String
,或者可能是getLine::()->String
。(()
是单位类型,其唯一值是()
;它有点像C语言中的void类型,但只有一个值。)但这意味着每次编写getLine
,它都必须返回相同的字符串,这不是您想要的。这就是IO
类型的目的:封装操作。这些行动不同于职能;它们代表着不纯的计算(尽管它们本身是纯的)。类型为IO A
的值表示执行时返回类型为A
的值的操作。因此,getLine
具有类型getLine::IO String
:每次计算操作时,都会生成一个字符串(通过从用户读取)。类似地,putStr
具有类型putStr::String->IO()
;这是一个函数,它接受一个字符串并返回一个操作,该操作在运行时不会返回任何有用的信息……但是,作为一个副作用,它会将一些内容打印到屏幕上
您正在尝试编写类型为IO()->([Char],Int)
的函数。这将是一个函数,它接受一个操作作为输入,并返回一个元组,这不是您想要的。您需要一个IO(String,Int)
——一个操作,在运行时生成一个元组,由一个字符串(它是[Char]
的同义词)和一个整数组成。你现在的代码也快到了!这是您需要的:
investinput :: IO (String, Int)
investinput = do
putStrLn "Enter Username : "
username <- getLine
putStrLn "Enter Invest Amount : "
tempamount <- getLine
let amount = read tempamount
return (username, amount)
investinput::IO(字符串,Int)
输入=do
putStrLn“输入用户名:”
用户名字符串
:这是一个函数,它接受任何可以显示的内容,并生成一个表示该内容的字符串。您需要的是read
,它的类型为reada=>String->a
:给定一个字符串,它将解析它并返回一些可读值
您询问的另一件事是返回元组(String,Int)
,而不是操作IO(String,Int)
。没有纯粹的方法可以做到这一点;换句话说,没有纯函数ioa->a
。为什么会这样?因为IO a
代表了一种依赖于现实世界的不纯行为。如果我们有这样一个函数impossibleRunIO::IO a->a
,那么我们希望它是impossibleRunIO getLine==impossibleRunIO getLine
,因为函数必须是纯函数。但这是没有用的,因为我们希望不可能的runio
能够与现实世界真正交互!因此,这种纯粹的功能是不可能的。任何进入IO的东西都不能离开。这就是return
的作用:在本例中,它是一个类型为return::a->IO a
的函数,可以将纯值放入IO
。对于任何x
,return x
是一个操作,在运行时总是产生x
。这就是为什么您必须用return
结束do
块的原因:username
是从操作中提取的纯值,因此仅在do
块中可见。在外界看到它之前,你需要将它提升到IO
。金额
/临时金额
也是如此
为了完整起见:这背后有一个总的理论将其联系在一起。但对于开始Haskell编程来说,这根本不是必需的。我建议您将大部分代码结构化为纯函数,折叠、旋转和破坏数据。然后构造一个薄的(尽可能薄的)IO
前端层,该层与所述功能交互。你会惊讶于你所需要的IO是多么少
1:它实际上有一个更通用的类型,但目前还不相关。关于返回(String,Int)
而不是IO(String,Int)
的问题的答案很简单:你不能。一旦你进入IO
你就会被困在那里。这就是人们说Haskell是一种“纯”语言的部分含义
您想要做的与您在这里使用getLine
所做的类似。getLine
的类型是IO字符串
。写入用户名时,请尝试删除类型签名,将show
更改为read
,并在添加read
的行末尾添加::Int
。然后将其加载到GHCi中,试用,并使用:t
请求类型。这将不是你在这里拥有的。谢谢,它可以工作,但为什么这个类型签名不起作用。investinput::IO()->([Char],Int)我需要返回元组
main = do
(name, amount) <- investinput
putStrLn $ name ++ " invested $" ++ show amount ++ "."
import Control.Monad (liftM)
investinput :: IO (String, Int)
investinput = do
putStrLn "Enter Username : "
username <- getLine
putStrLn "Enter Invest Amount : "
amount <- liftM read getLine -- We can also use liftM to get rid of tempamount.
return (username, amount)
summary :: (String, Int) -> String
summary (name, amount) = name ++ " invested $" ++ show amount ++ "."
main = putStrLn =<< liftM summary investinput