我是Haskell的完全初学者,虽然熟悉Python,F#,Java,C#和C++等语言的功能范例(以有限的方式).
只是一直在逃避我的事情是在哈斯克尔的IO.我尝试过几次,甚至在尝试绕过它的过程中学习了C#和F#.
更具体地说,我指的是不使用符号来获取IO,使用符号,IO变得微不足道.这可能是不好的做法,但在我的业余时间,我喜欢看看我是否可以用一个连续的表达来完成任务.这是一个很糟糕的做法,很有趣.
这样的表达式通常是那种(在伪haskell中):
main = getStdinContentsAsString
>>= ParseStringToDataStructureNeeded
>>= DoSomeComputations
>>= ConvertToString
>>= putStrLn
Run Code Online (Sandbox Code Playgroud)
我对最后四个部分没有任何问题.我学习F#的原因之一就是看看是否有什么东西我没有把我的脑袋放在IO之外,但是只要我有方便的F#的Console.ReadLine()它返回一个普通的老字符串它基本上是一帆风顺.
这让我再次回到了haskell,再次被IO机制所阻止.
我已经管理(在这里使用另一个问题)从控制台读取一个int,并打印"Hello World!" 很多次
main = (readLn :: IO Int) >>= \n -> mapM_ putStrLn $ replicate n "Hello World!"
Run Code Online (Sandbox Code Playgroud)
我想至少得到一些"通用"的方式只是读取stdin的整个内容(可能是多行,所以getContents需要是选择的函数)作为一个字符串,然后我可以使用其他功能,如取消,然后映射.
我已经尝试过的一些事情:
正如我所说,getContents将是我需要的(除非有一些相当于它).
使用逻辑,因为
getContents :: IO String
Run Code Online (Sandbox Code Playgroud)
然后我需要一些带有IO String的东西并返回一个旧的String.这是(据我所知)
unsafePerformIO :: IO a -> a
Run Code Online (Sandbox Code Playgroud)
但由于某些原因,ghc不满意:
* Couldn't match type `[Char]' with `IO (IO b)'
Expected type: String -> IO b
Actual type: IO (IO b) -> IO b
* In the second argument of `(>>=)', namely `unsafePerformIO'
In the expression: getContents >>= unsafePerformIO
Run Code Online (Sandbox Code Playgroud)
我试过的另一件事:这没有问题;
main = getContents >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
即使getContents返回的类型是IO操作,而不是putStrLn想要的本身String
getContents :: IO String
putStrLn :: String -> IO ()
Run Code Online (Sandbox Code Playgroud)
不知何故,动作被神奇地执行,结果字符串被传递给put函数.
但是当我尝试添加内容时,比如在打印之前简单地将"hello"添加到输入中:
main = getContents >>= (++ " hello") >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
我突然得到一个类型不匹配:
Couldn't match type `[]' with `IO'
Expected type: String -> IO Char
Actual type: [Char] -> [Char]
* In the second argument of `(>>=)', namely `(++ " hello")'
In the first argument of `(>>=)', namely
`getContents >>= (++ " hello")'
In the expression: getContents >>= (++ " hello") >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
不知何故,IO动作不再执行(或者我可能不理解这一点).
我自己也尝试了许多东西,用的组合getLine,readLn,getContents,unsafePerformIO,read,fmap无济于事.
这只是一个非常基本的例子,但它完全说明了让我几次放弃haskell的问题(可能我不是唯一一个),虽然顽固的想要了解它,并了解什么是几乎这些函数式编程语言让我回归.
总结:
有没有我没有得到的东西?(99%是的)
如果是,那又怎样?
我应该如何阅读整个标准输入并在一个连续的表达式中处理它?(如果我只需要一行,我想无论解决方案是什么,它都适用于getLine正弦它基本上是getContents的姐妹)
提前致谢!
mel*_*ene 11
你不考虑的主要事情似乎是>>=:
(>>=) :: IO a -> (a -> IO b) -> IO b
Run Code Online (Sandbox Code Playgroud)
换句话说,你不需要"打开" IO String到String; 该>>=运营商已经把一个普通String其右操作数(功能):
getContents >>= (\s -> ...)
-- ^ s :: String
Run Code Online (Sandbox Code Playgroud)
getContents >>= (++ " hello")失败的原因是>>=需要函数返回一个IO ...值,但是(++ "hello") :: String -> String.
您可以通过添加return :: a -> IO a到混合中来解决此问题:
getContents >>= (return . (++ "hello"))
Run Code Online (Sandbox Code Playgroud)
整个表达式都有类型IO String.执行时,它将读取数据stdin,附加"hello"到它,并返回结果字符串.
从而,
getContents >>= (return . (++ "hello")) >>= putStrLn
Run Code Online (Sandbox Code Playgroud)
应该工作正常.但它比必要的更复杂.从概念上讲,再次return包装一个值IO并将>>=其展开(有点).
我们可以融合右边的return/ >>=位:
getContents >>= (\s -> putStrLn (s ++ "hello"))
Run Code Online (Sandbox Code Playgroud)
即不是采取getContents :: IO String,添加"hello"它以形成一个新的IO String动作,然后附加putStrLn :: String -> IO ()到它,我们包装putStrLn以创建一个新的String -> IO ()功能("hello"在将事物交给之前附加到其参数putStrLn).
现在,如果我们想要,我们可以摆脱s标准的免费技巧:
getContents >>= (putStrLn . (++ "hello"))
Run Code Online (Sandbox Code Playgroud)
有关的注意事项IO一般:要记住的事情是,IO ...是正常的Haskell类型.这里没有神奇的事情发生.>>=不执行任何行动; 它只是组合了一个类型的值IO something和一个函数来构造一个新的类型值IO somethingelse.
您可以将Haskell视为纯粹的元语言,将构造命令性程序(即执行指令列表)构建为内存中的数据结构.实际执行的唯一事情是绑定的值Main.main.也就是说,它就像一个命令式运行时运行你的Haskell代码来生成一个纯值main :: IO ().然后,该值的内容将作为命令性指令执行:
main :: IO ()
main =
putChar 'H' >>
putChar 'i' >>
putChar '\n'
Run Code Online (Sandbox Code Playgroud)
main绑定到表示命令性程序的数据结构print 'H'; print 'i'; print newline.运行Haskell程序构建此数据结构,然后运行时执行它.
但是,此模型并不完整:命令式运行时可以回调Haskell代码.>>=可以用来在命令式代码中"嵌入"Haskell函数,然后可以(在运行时)检查值,决定下一步做什么,等等.但所有这些都以纯Haskell代码的形式发生; 只有IO从返回值f的x >>= f事项(f本身有没有副作用).
| 归档时间: |
|
| 查看次数: |
581 次 |
| 最近记录: |