与IO String到String
之间存在差异我想从IO中获取一些String值。
任何人都可以告诉我这个问题。我很无能
答案 0 :(得分:6)
问题是您希望在程序运行时使用String
操作导致的IO String
值。你写的就好像你已经把手放在绳子上,但你没有。
或者:你写的就好像你已经定义或隔离了一个字符串,但你没有。到目前为止,您已经定义或隔离了一个返回字符串的操作。执行该操作的个别情况将返回不同的字符串。
据推测,您正在尝试定义更复杂的操作 - 某种类型为IO Blah
- 可能类型IO ()
类型可以编译为可执行文件的类型。我们的想法是,在更复杂的操作中,通过执行类型String
的操作(即您迄今为止定义的操作)来获得IO String
值 - 复杂操作的执行者将继续做一些取决于该价值的东西。这是由String -> IO Blah
类型的函数表示的东西 - 也许是String -> IO ()
当然,这样的函数不会将IO String
值(即返回字符串的操作)作为参数,而String
值作为参数。我们不能直接加入他们。
要从您的操作返回字符串 - 您的IO String
值 - 以及'字符串 - > IO Blah的功能,一个新的 - 一个返回一个等等的动作 - 我们通过函数>>=
加入它们。专门针对此案例>>=
的类型为IO String -> (String -> IO Blah) -> IO Blah
- 可能是IO String -> (String -> IO ()) -> IO ()
因此,要考虑一对此类事情的最简单示例,请考虑getLine
和putStrLn
。
getLine
找出刚刚输入的字符串的动作 - 它的类型为IO String
。
您可能会说putStrLn
在屏幕上打印String
值,然后返回左边距。但这很肤浅:完成的确切事情取决于String
值的规范,因此它的类型为String -> IO()
。也就是说:putStrLn
没有做任何事情,它是一个将字符串映射到可以完成的事情的函数。像往常一样,你可以在其范围类型中定义一个值(动作,即IO ()
)通过在函数符号后面跟着域类型中的某些东西的名称(字符串,即String
)所以组合putStrLn "Gee whiz"
命名一个明确的动作,某事类型为IO ()
。
ghci
将动态执行此类操作,因此,对于任何字符串,例如“Gee whiz”,您可以编写putStrLn "Gee whiz"
并立即“执行此操作” - 写作的动作“ Gee whiz“到屏幕并返回左边距。
Prelude> putStrLn "Gee whiz"
Gee whiz
Prelude>
同样,单字符字符串中只包含Unix响铃字符\BEl
,是我们用'\BEl':[]
或['\BEL']
或"\BEL"
命名的字符串。对于该字符串作为参数,putStrLn
对于值有一种听起来完全不同的动作。我们得到
Prelude> putStrLn "\BEL"
Prelude>
在这里你会听到Unix铃声回到左边距之前。这是一个非常蹩脚的音频节目,但你有。 ghci
执行启动Unix响铃的操作,在按返回之前使用单词putStrLn "\BEL"
命名的操作。
所以无论如何getLine
是IO String
类型的值,你想“从IO获取这个字符串值”。当然,它还不存在,它取决于用户输入的内容。但是我们可以考虑一下该程序在得到它时如何处理这样的值。我们可以通过指定从字符串到动作的函数来指定它,例如putStrLn
。因此,我们可以通过使用>>=
或do
符号糖组合来定义一个“获取值”的完整操作并以某种方式使用它。
最简单的案例就像echo
:
echo :: IO ()
echo = getLine >>= putStrLn
或等效
echo = getLine >>= (\x -> putStrLn x)
或do
符号:
echo = do
the_string_i_want_to_take <- getLine
putStrLn the_string_i_want_to_take
或更少荒谬:
echo = do
x <- getLine
putStrLn x
当然,你想要“拿绳子”并且可能在完成之前弄乱它。
reverseEcho :: IO ()
reverseEcho = getLine >>= (\x -> putStrLn (reverse x))
或更紧凑:
reverseEcho = getLine >>= (putStrLn . reverse)
或do
符号:
reverseEcho = do
the_string_i_want_to_take <- getLine
putStrLn (reverse the_string_i_want_to_take)
或更少荒谬:
reverseEcho = do
x <- getLine
putStrLn (reverse x)
如果你想把'扭转字符串'看作是在获取和打印之间用字符串完成的东西,你可以写:
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)
或
reverseEcho = do
x <- getLine
y <- return x
putStrLn y
或等效
reverseEcho = (getLine >>= (return . reverse)) >>= putStrLn
此处括号不是必需的,因为.
和>>=
的优先级已经过适当优化。但(getLine >>= (return . reverse))
只是“返回字符串的操作”的另一个名称,值IO String
,而不是字符串本身。您无法直接应用String -> Whatever
函数来获取Whatever
,但您可以通过>>=
将其与字符串中的函数组合到操作。
同样
reverseFileAA :: IO ()
reverseFileAA = readFile "AA.txt" >>= writeFile "reversedAA.txt" . reverse
是编写名为“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
答案 1 :(得分:4)
IO String是IO-Monad中的String。如果IO-Monad中的函数返回IO字符串,则通过执行以下操作获取String:
do str <- ioFunc
当IO-Monad需要IO访问并且必须返回IO类型时,它就在IO-Monad中。