Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell输入返回元组_Haskell_Io_Interactive - Fatal编程技术网

Haskell输入返回元组

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

我想知道IO()函数能否返回元组,因为我想从这个函数中获取元组作为另一个函数的输入

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