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