Haskell中的IO类型是什么
我是Haskell编程语言的新手,在Haskell中的IO类型是什么,haskell,Haskell,我是Haskell编程语言的新手,在IO类型上,我一直磕磕绊绊,要么作为函数参数,要么作为返回类型 playGame :: Screen -> IO () 或 这是如何工作的,我有点困惑,因为我知道字符串需要单词,Int需要数字。函数中使用的IO期望或返回什么?简单地说: f1 :: A -> B -> C 是一个函数,它接受a和B类型的两个参数,并返回aC。它不执行任何IO f2 :: A -> B -> IO C 与f1类似,但也可以执行IO f3 ::
IO
类型上,我一直磕磕绊绊,要么作为函数参数,要么作为返回类型
playGame :: Screen -> IO ()
或
这是如何工作的,我有点困惑,因为我知道字符串需要单词,Int需要数字。函数中使用的IO
期望或返回什么?简单地说:
f1 :: A -> B -> C
是一个函数,它接受a
和B
类型的两个参数,并返回aC
。它不执行任何IO
f2 :: A -> B -> IO C
与f1类似,但也可以执行IO
f3 :: (A -> B) -> IO C
将函数a->B
(不执行IO)作为参数,并生成一个C
,可能执行IO
f4 :: (A -> IO B) -> IO C
f5 :: A -> IO B -> IO C
将函数a->iob
(可以执行IO)作为参数,并生成一个C
,可能执行IO
f4 :: (A -> IO B) -> IO C
f5 :: A -> IO B -> IO C
将类型为a
的值作为参数,类型为IO B
的IO操作,并返回类型为C
的值,可能执行IO(例如,通过运行IO操作参数一次或多次)
例如:
f6 :: IO Int -> IO Int
f6 action = do
x1 <- action
x2 <- action
putStrLn "hello!"
x3 <- action
return (x1+x2+x3)
可以使用以下参数调用函数:
arg1 :: IO String
arg1 = do
putStrLn "hello"
s <- readLine
return ("here: " ++ s)
arg2 :: String -> IO ()
arg2 str = do
putStrLn "hello"
putStrLn str
putStrLn "hello again"
arg3 :: Screen
arg3 = ... -- I don't know what's a Screen in your context
arg1::IO字符串
arg1=do
putStrLn“你好”
s IO()
arg2 str=do
putStrLn“你好”
putStrLn街
putStrLn“你好”
arg3::屏幕
arg3=…--我不知道在你的上下文中什么是屏幕
IO
是Haskell区分引用透明代码和非引用透明代码的方式IO a
是返回a
的IO操作类型
您可以将IO操作视为一段代码,对等待执行的真实世界有一定影响。由于这种副作用,IO操作在引用上是不透明的;因此,执行令很重要。Haskell程序的main
函数的任务是正确排序和执行所有IO操作。因此,当您编写一个返回IO a
的函数时,您实际上是在编写一个返回操作的函数,该操作最终在main
执行时执行该操作并返回a
更多解释:
引用透明度意味着您可以用函数的值替换函数。引用透明函数不能有任何副作用;特别是,引用透明函数无法访问任何硬件资源,如文件、网络或键盘,因为函数值将取决于其参数以外的其他内容
像Haskell这样的函数语言中的引用透明函数类似于数学函数(域和codomain之间的映射),远不止一系列关于如何计算函数值的命令式指令。因此,Haskell代码告诉编译器一个函数应用于它的参数,但它并没有说一个函数被调用并因此被实际计算
因此,引用透明函数并不意味着执行顺序。Haskell编译器可以以它认为合适的任何方式对函数进行求值,或者在不需要的情况下根本不求值(称为惰性求值)。当一个函数需要另一个函数的输出作为输入时,唯一的排序来自数据依赖关系
现实世界的副作用在参考上是不透明的。你可以把现实世界想象成某种隐含的全局状态,有效函数会发生变化。由于这种状态,执行顺序很重要:如果先从数据库中读取数据,然后再对其进行更新,则执行顺序会有所不同,反之亦然
Haskell是一种纯函数式语言,它的所有函数都是引用透明的,编译依赖于这一保证。那么,我们如何处理操纵某些全局真实世界状态并需要按特定顺序执行的有效函数呢?通过在这些函数之间引入数据依赖关系
这正是IO所做的:在引擎盖下,IO类型将一个有效函数与一个伪状态参数包装在一起。每个IO操作都将此虚拟状态作为输入,并将其作为输出提供。将这个伪状态参数从一个IO操作传递到下一个IO操作会创建一个数据依赖项,从而告诉Haskell编译器如何正确地对所有IO操作进行排序
您看不到虚拟状态参数,因为它隐藏在一些语法糖后面:
main
中的do
符号和其他IO操作,以及IO
类型中。让我们先试着回答一些简单的问题:
- Haskell中的
可能
类型是什么 摘自《公约》第21章(第205页): 这是一种简单的部分类型-您有一个值(通过
)或者没有(只是
)无
- 这是怎么回事
让我们看一下
的一个可能的Maybe
实例:Monad
此单元接口简化了基于instance Monad Maybe where return = Just Just x >>= k = k x Nothing >>= _ = Nothing
可能
构造函数的值的使用,例如。 而不是:
你可以简单地写下:\f ox oy -> case ox of Nothing -> Nothing Just x -> case oy of Nothing -> Nothing Just y -> Just (f x y)
一元接口的应用非常广泛:从解析到封装状态,等等\f ox oy -> ox >>= \x -> oy >>= \y -> return (f x y)
- 函数中使用的
类型期望或返回什么 对于需要基于可能
的值的函数,例如:
maybe :: b -> (a -> b) -> Maybe a -> b maybe _ f (Just x) = f x maybe d _ Nothing = d
invert :: Double -> Maybe Double invert 0.0 = Nothing invert d = Just (1/d)
echo :: IO () echo :: getChar >>= \c -> if c == '\n' then return () else putChar c >> echo
如果函数中正在使用其内容,则函数可能必须处理未接收其可以使用的值的问题,即newLine :: IO () newLine = putChar '\n'
对于返回基于无
的值的函数,例如:
maybe :: b -> (a -> b) -> Maybe a -> b maybe _ f (Just x) = f x maybe d _ Nothing = d
invert :: Double -> Maybe Double invert 0.0 = Nothing invert d = Just (1/d)
echo :: IO () echo :: getChar >>= \c -> if c == '\n' then return () else putChar c >> echo
它只需要使用适当的构造函数 最后一点:观察基于newLine :: IO () newLine = putChar '\n'
的值是如何使用的-从简单开始(例如
或反转0.5
),然后定义其他可能更复杂的基于只是“这里”
的值(使用
,(>=)
,等等)到(>>)