Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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中的IO类型是什么_Haskell - Fatal编程技术网

Haskell中的IO类型是什么

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 ::

我是Haskell编程语言的新手,在
IO
类型上,我一直磕磕绊绊,要么作为函数参数,要么作为返回类型

playGame :: Screen -> IO ()

这是如何工作的,我有点困惑,因为我知道字符串需要单词,Int需要数字。函数中使用的
IO
期望或返回什么?

简单地说:

f1 :: A -> B -> C
是一个函数,它接受
a
B
类型的两个参数,并返回a
C
。它不执行任何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
    只是“这里”
    ),然后定义其他可能更复杂的基于
    的值(使用
    (>=)
    (>>)
    ,等等)到