Purescript效果:防止深层嵌套

时间:2018-01-20 22:21:18

标签: purescript

目前,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

3 个答案:

答案 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),您就可以使用traversesequence

具体来说,您的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的新类型(在我们的例子中mEff (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