我需要一些包装在 IO 类型上,但我不能“强制”haskell 在包装器中运行 IO 操作。我尝试为它使用 bang 模式,但它也不起作用。
我在更简单的类型上重新创建了问题。下面的代码片段
{-# LANGUAGE BangPatterns #-}
newtype IOWrapper a = IOWrapper (IO a)
mkWrapper :: IO a -> IOWrapper a
mkWrapper !a = IOWrapper a
foo :: IO ()
foo = putStrLn "foo" --Shows "foo" on console, as expected
bar :: IOWrapper ()
bar = IOWrapper $ putStrLn "bar" --Shows nothing
baz :: IOWrapper ()
baz = mkWrapper $ putStrLn "baz" --Shows nothing
Run Code Online (Sandbox Code Playgroud)
你不能这样做(不作弊)。评估 IO 不会使其发挥作用。导致 IO 执行效果的唯一方法是将其包含在特殊动作中main :: IO a
,通常是将多个较小的动作组合成一个大的 IO 动作。
与其问怎么做这件事,倒不如回想一下你为什么想做这件事。而是询问如何实现您最初的目标。
仅仅调用putStrLn "foo"
实际上并不打印“foo”。相反,它创建了一个“动作”,然后必须单独“执行”,然后才会打印“foo”。而且,你实际上可以多次“执行”它,效果也会产生多次。
“执行”一个IO
动作的唯一方法是让它成为入口点——即main
函数——或者入口点的一部分,或者另一个函数的一部分,它本身就是入口点的一部分,等等。入口点是所有效果的根,在它之外没有效果执行。
您的foo
函数可能看起来“有效”,因为您在 GHCi 中运行它,对吗?如果是这样,那么它会作为 GHCi 自己的入口点的一部分执行。GHCi 识别IO
类型的事物并立即执行它们。
但是 GHCi 不识别该IOWrapper
类型的东西,所以它不会解包和执行它们。
所以你唯一的办法就是解开并执行自己:
runIOWrapper :: IOWrapper a -> IO a
runIOWrapper (IOWrapper a) = a
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样在 GHCi 中运行你的包装动作:
> runIOWrapper bar
bar
> runIOWrapper baz
baz
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
92 次 |
最近记录: |