目前,main
具有以下签名:
main :: Eff (dom :: DOM) (Maybe (Eff (dom :: DOM) (Maybe Element)))
我想要以下内容:
main :: Eff (dom :: DOM) (Maybe Element)
findItem :: forall e. IsElement e => e -> Eff (dom :: DOM) (Maybe Element)
findItem e = getElementsByClassName "thing" (toElement e) >>= (item 0)
-- main :: Eff (dom :: DOM) (Maybe Element)
main = (map findItem) <$> (window >>= document >>= body)
这样做的最佳方式是什么?
当然,我可以做到以下几点:
findItem :: forall e. IsElement e => Maybe e -> Eff (dom :: DOM) (Maybe Element)
findItem (Just e) = getElementsByClassName "findItemEdit" (toElement e) >>= (item 0)
findItem Nothing = pure Nothing
main :: Eff (dom :: DOM) (Maybe Element)
main = findItem =<< body =<< document =<< window
但我希望Maybe
函数中没有处理findItem
。
答案 0 :(得分:3)
使用traverse :: forall a b eff. (a -> Eff eff b) -> Maybe a -> Eff eff (Maybe b)
。功能更通用,但这就是你想要使用它的方式。每当您发现自己想要“交换”两种类型时,例如Maybe a -> Eff eff (Maybe a)
或Maybe (List a) -> List (Maybe a)
,您就可以使用traverse
或sequence
。
具体来说,您的main
看起来像是:
main :: Eff (dom :: DOM) (Maybe Element)
main = do
mdocBody <- window >>= document >>= body
mmitem <- traverse findItem mdocBody
-- mmitem has type `Maybe (Maybe Element)`
-- we can use `join` to collapse
pure (join mmitem)
或者,无点,
main :: Eff (dom :: DOM) (Maybe Element)
main =
window >>= document >>= body
>>= map join <<< traverse findItem
答案 1 :(得分:3)
您可以使用MaybeT monad变换器:
main = runMaybeT do
b <- MaybeT (window >>= document >>= body)
MaybeT (findItem b)
MaybeT
是包含在monad Maybe
内的m
的新类型(在我们的例子中m
是Eff (dom :: DOM)
):
newtype MaybeT m a = MaybeT (m (Maybe a))
及其bind
按照您希望的方式处理嵌套和取消:
bind (MaybeT x) f = MaybeT do
x >>= case _ of
Nothing -> pure Nothing
Just y -> case f y of MaybeT m -> m
答案 2 :(得分:0)
我能想到的最好的方法是使用Maybe
catamorphism,它基本上会从你的第一个例子中取出findItem
并从第二个例子变成findItem
:
main :: Eff (dom :: DOM) (Maybe Element)
main = maybe (pure Nothing) findItem =<< body =<< document =<< window