Chr*_*ris 2 io monads haskell purely-functional
为了用一个简单的例子说明这一点,请说我已经实现了filter:
filter :: (a -> Bool) -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
我有一个p与现实世界相互作用的谓词:
p :: a -> IO Bool
Run Code Online (Sandbox Code Playgroud)
如何在filter不编写单独的实现的情况下使其工作:
filterIO :: (a -> IO Bool) -> [a] -> IO [a]
Run Code Online (Sandbox Code Playgroud)
大概如果我可以p变成p':
p': IO (a -> Bool)
Run Code Online (Sandbox Code Playgroud)
然后我就能做到
main :: IO ()
main = do
p'' <- p'
print $ filter p'' [1..100]
Run Code Online (Sandbox Code Playgroud)
但我一直无法找到转换.
编辑: 正如人们在评论中指出的那样,这样的转换没有意义,因为它会破坏IO Monad的封装.
现在的问题是,我可以构建我的代码,以便纯和IO版本不完全复制核心逻辑吗?
如何在不编写单独的实现的情况下使其与过滤器一起使用
这是不可能的,事实上这种事情是不可能的 - 设计--Haskell对其类型设置了严格的限制,你必须遵守它们.你不能IO无所畏惧地洒遍这个地方.
现在的问题是,我可以构建我的代码,以便纯和IO版本不完全复制核心逻辑吗?
你会感兴趣的filterM.然后,您可以filterIO使用IOmonad和使用monad的纯功能来获得两种功能Identity.当然,对于纯粹的情况,您现在必须支付包装/解包(或包装coerce)Identity包装的额外费用.(边注:由于Identity是newtype,这仅仅是一个代码的可读性成本,而不是一个运行一个)
ghci> data Color = Red | Green | Blue deriving (Read, Show, Eq)
Run Code Online (Sandbox Code Playgroud)
下面是一个monadic示例(注意,只含有该线Red,Blue和Blue在提示被用户输入的):
ghci> filterM (\x -> do y<-readLn; pure (x==y)) [Red,Green,Blue]
Red
Blue
Blue
[Red,Blue] :: IO [Color]
Run Code Online (Sandbox Code Playgroud)
这是一个纯粹的例子:
ghci> filterM (\x -> Identity (x /= Green)) [Red,Green,Blue]
Identity [Red,Blue] :: Identity [Color]
Run Code Online (Sandbox Code Playgroud)