考虑以下Haskell程序.我试图以"流式"编程,其中函数在流上运行(这里简单地作为列表实现).像normalStreamFunc这样的东西适用于懒惰列表.我可以将无限列表传递给normalStreamFunc并有效地获取另一个无限列表,但是将函数映射到每个值.像effectivefulStreamFunc这样的东西不能很好地工作.IO操作意味着我需要先评估整个列表,然后才能提取单个值.例如,程序的输出是这样的:
a
b
c
d
"[\"a\",\"b\"]"
Run Code Online (Sandbox Code Playgroud)
但我想要的是一种编写effectfulStreamFunc的方法,以便程序生成:
a
b
"[\"a\",\"b\"]"
Run Code Online (Sandbox Code Playgroud)
留下剩下的行动没有评估.我可以想象一个使用unsafePerformIO的解决方案,但是假设我把它从表中拿走了.这是程序:
import IO
normalStreamFunc :: [String] -> [String]
normalStreamFunc (x:xs) = reverse(x) : normalStreamFunc xs
effectfulStreamFunc :: [String] -> IO [String]
effectfulStreamFunc [] = return []
effectfulStreamFunc (x:xs) = do
putStrLn x
rest <- effectfulStreamFunc xs
return (reverse(x):rest)
main :: IO ()
main = do
let fns = ["a", "b", "c", "d"]
es <- effectfulStreamFunc fns
print $ show $ take 2 es
Run Code Online (Sandbox Code Playgroud)
更新:
谢谢大家的有益和深思熟虑的反馈.我之前没有见过sequence操作员,这对了解有帮助.我曾想过一种(不那么优雅)传递IO(字符串)值而不是字符串的方法,但对于编程风格的用途有限,因为我希望其他流函数对字符串本身起作用,而不是可以产生字符串的动作.但是,基于对其他回答的思考,我想我明白为什么这一般无法解决.在我提出的简单案例中,我真正想要的是sequence运算符,因为我认为流顺序意味着对操作的排序.事实上,不一定暗示这种排序.当我考虑以两个流作为输入的流函数时(例如,成对添加两个流),这对我来说变得更加清晰.如果两个"传入"流都执行IO,那么这些IO动作的顺序是不确定的(当然,除非我们通过在IO monad中对它进行排序来定义它).问题解决了,谢谢大家!
因此,似乎Happy是Haskell中yacc的强大替代品.是否有同样强大的词法生成器来替换lex/flex?
GHC默认会对以下函数执行尾调用优化吗?关于它的唯一奇怪的事情是它递归地定义了一个IO动作,但我不明白为什么这不是TCO.
import Control.Concurrent.MVar
consume :: MVar a -> [a] -> IO ()
consume _ [] = return ()
consume store (x:xs) = do putMVar store x
consume store xs
Run Code Online (Sandbox Code Playgroud) 我有一个Haskell类型类问题.我无法通过语法来获得在GHC下编译的这个(看似合理的)程序.
import Control.Concurrent.MVar
blah1 :: [a] -> IO ([a])
blah1 = return
blah2 :: [a] -> IO (MVar [a])
blah2 = newMVar
class Blah b where
blah :: [a] -> IO (b a)
instance Blah [] where
blah = blah1
-- BOOM
instance Blah (MVar []) where
blah = blah2
main :: IO ()
main = do
putStrLn "Ok"
Run Code Online (Sandbox Code Playgroud)
我收到以下错误消息,哪种有意义,但我不知道如何解决它:
`[]' is not applied to enough type arguments
Expected kind `*', but `[]' has kind `* -> *'
In the …Run Code Online (Sandbox Code Playgroud) 在OCaml 3.11中,我想使用include指令"扩展"现有模块,如下所示:
module MyString = struct
include String
let trim s = ...
end
Run Code Online (Sandbox Code Playgroud)
没问题.但现在我想明确地公开这个模块的类型(即在.mli文件中).我想要这样的东西:
module MyString : sig
include String
val trim : string -> string
end
Run Code Online (Sandbox Code Playgroud)
但是include语法不正确,因为String指的是模块,而不是模块类型(编译器确实是barf).我如何在这里引用String的模块类型(没有在sig表达式中明确地写出来)?
谢谢!