什么是IO String和Haskell中的普通字符串之间的区别

Nub*_*iya 1 monads haskell types

是否存在从IO String到String的区别

我想从IO中获取一些String值.

任何人都可以告诉我这个问题.我一无所知

Art*_*hur 6

问题是,当程序运行时,您希望如何处理动作将产生的StringIO String.你写的就好像你已经把手放在绳子上,但你没有.

或者:你写的就好像你已经定义或隔离了一个字符串,但你没有.到目前为止,您已定义或隔离了一个返回字符串的操作.执行该操作的个别情况将返回不同的字符串.

大概你正试图定义一个更复杂的动作 - 某种类型的IO Blah东西 - 也许是IO ()可以编译成可执行文件的类型.我们的想法是,在更复杂的行动中,String通过执行类型IO String的行动(即您迄今为止定义的行动)来获得价值- 复杂行动的执行者将继续做一些取决于什么的事情.那个价值是.这是由类型的函数表示的东西String -> IO Blah- 也许String -> IO ()

当然,这样的函数不会将IO String值(即返回字符串的操作)作为参数,而将String值作为参数.我们不能直接加入他们.

要从你的操作返回一个字符串 - 你的IO String值 - 和一个'String - > IO Blah'函数,到一个新的东西 - 一个返回一个blah动作 - 我们通过该函数加入它们>>=.专门针对这种情况>>=有类型IO String -> (String -> IO Blah) -> IO Blah- 它可能是IO String -> (String -> IO ()) -> IO ()

所以,要考虑一对这样的事情的最简单的例子,考虑getLineputStrLn.

getLine找出刚刚输入的字符串的动作 - 它具有类型IO String.

您可能会说在屏幕上putStrLn 打印一个String值然后返回到左边距.但那是肤浅的:做了什么确定的事情取决于String值的规范,所以它有类型String -> IO().这就是说:putStrLn什么都不做,它是一个将字符串映射到可以完成的事情的函数. 像往常一样,你可以IO ()通过在函数符号中使用域类型中的某个名称(字符串,即String)来定义其范围类型(​​操作,即's)中的值.因此,组合putStrLn "Gee whiz"命名一个明确的操作,类型的东西IO ().

ghci将会动态执行此类操作,因此,对于任何字符串,如"Gee whiz",您可以编写putStrLn "Gee whiz"并立即"执行此操作" - 将"Gee whiz"写入屏幕并返回左边距的操作.

Prelude> putStrLn "Gee whiz"
Gee whiz
Prelude> 
Run Code Online (Sandbox Code Playgroud)

同样,一个字符的字符串,只是具有Unix的钟声人物\BEl在里面,是我们与命名字符串'\BEl':[]['\BEL']"\BEL".对于该字符串作为参数,putStrLn对于值有一种听起来完全不同的动作.我们得到了

Prelude> putStrLn "\BEL"

Prelude> 
Run Code Online (Sandbox Code Playgroud)

在这里你会听到Unix铃声回到左边距之前.这是一个相当蹩脚的音频节目,但你有. ghci正在执行敲响Unix铃声的动作,putStrLn "\BEL"在按下返回之前用单词命名的动作.

所以无论如何getLine都是类型的值,IO String你想"从IO获取这个字符串值".当然,它还不存在,它取决于用户输入的内容.但是我们可以考虑一下该程序在得到它时如何处理这样的值.我们可以通过指定从字符串到动作的函数来指定它,例如putStrLn.因此,我们可以定义一个"取值"的完整动作,并通过用它们>>=或用do符号糖组合它们以某种方式使用它.

最琐碎的案例是echo:

echo :: IO ()
echo = getLine >>= putStrLn
Run Code Online (Sandbox Code Playgroud)

或者等价的

echo = getLine >>= (\x -> putStrLn x)
Run Code Online (Sandbox Code Playgroud)

或用do符号表示:

echo = do 
     the_string_i_want_to_take <- getLine
     putStrLn the_string_i_want_to_take
Run Code Online (Sandbox Code Playgroud)

或者不那么荒谬:

echo = do 
     x <- getLine
     putStrLn x
Run Code Online (Sandbox Code Playgroud)

当然,你想要"拿绳子",也许在完成之前搞乱它.

reverseEcho :: IO ()
reverseEcho = getLine >>= (\x -> putStrLn (reverse x))
Run Code Online (Sandbox Code Playgroud)

或者更紧凑:

reverseEcho = getLine >>= (putStrLn . reverse)
Run Code Online (Sandbox Code Playgroud)

或用do符号表示:

reverseEcho = do 
        the_string_i_want_to_take <- getLine
        putStrLn (reverse the_string_i_want_to_take)
Run Code Online (Sandbox Code Playgroud)

或者不那么荒谬:

reverseEcho = do 
        x <- getLine
        putStrLn (reverse  x)
Run Code Online (Sandbox Code Playgroud)

如果你想把'反转字符串'看作是在获取和打印之间用字符串完成的东西,你可以写:

reverseEcho = do 
        the_string_i_want_to_take <- getLine
        the_string_after_i_have_processed_it <- return (reverse the_string_i_want_to_take)
        putStrLn (the_string_after_i_have_processed_it)
Run Code Online (Sandbox Code Playgroud)

要么

reverseEcho = do
        x <- getLine
        y <- return x
        putStrLn y
Run Code Online (Sandbox Code Playgroud)

或者等价的

reverseEcho = (getLine >>= (return . reverse)) >>= putStrLn 
Run Code Online (Sandbox Code Playgroud)

这里括号不是必需的,因为优先级.>>=适当优化.但(getLine >>= (return . reverse))它只是"返回字符串的操作"的另一个名称,值为IO String,而不是字符串本身.你不能申请一个String -> Whatever直接函数将其拿到Whatever,但你可以用函数从字符串结合起来,以行动通过>>=.

同样

reverseFileAA :: IO ()
reverseFileAA = readFile "AA.txt" >>= writeFile "reversedAA.txt" . reverse
Run Code Online (Sandbox Code Playgroud)

写入一个名为"reversedAA.txt"的文件的操作,其中包含与其中的字符串相反的文件AA.txt,无论它是什么,都可能被写入

reverseFileAA = do
     old_file_contents <- readFile "AA.txt"
     new_file_contents <- return (reverse old_file_contents)
     writeFile "reversedAA.txt" old_file_contents
Run Code Online (Sandbox Code Playgroud)


ste*_*anv 5

IO 字符串是 IO-Monad 中的字符串。如果 IO-Monad 中的函数返回 IO 字符串,则可以通过执行以下操作来获取该字符串:

do str <- ioFunc
Run Code Online (Sandbox Code Playgroud)

当函数需要 IO 访问并且必须返回 IO 类型时,它就位于 IO-Monad 中。