如何到内心也许monad从purescript中的html按钮中提取类名?

vt5*_*491 7 html purescript

我正在努力学习purescript.

我在某些HTML中有一个按钮,我正在尝试打印类名.我正在建设和browserifying使用pulp.

我正在使用的函数是querySelector:

import Web.DOM.ParentNode (querySelector)
Run Code Online (Sandbox Code Playgroud)

这会在两个"框"内返回我想要的项目Element:一个外部效果monad和一个嵌入的Maybe monad:

> :type querySelector
QuerySelector -> ParentNode -> Effect (Maybe Element)
Run Code Online (Sandbox Code Playgroud)

我的效果monad看起来像:

getBtn ::  Effect Unit
getBtn = do
  doc <- map toParentNode (window >>= document)
  button <- querySelector (wrap "#btn") doc
  ... Need to extract class name from 'button' here
Run Code Online (Sandbox Code Playgroud)

我知道我可以通过在外部效果monad上调用bind(>> =)来到内部.我的第一个攻击计划是使用可能的功能手动取消装箱.以下是如何为简单的Int执行此操作:

> maybe 0 (\x -> x) $  Just 7
7
Run Code Online (Sandbox Code Playgroud)

对于一个可能的元素,我认为它看起来像:

unboxMaybeElement :: Maybe Element -> Element
unboxMaybeElement Nothing = Nothing
unboxMaybeElement (Just a) = maybe (Element ..note: trying to create a default element here) (\x -> x) a 
Run Code Online (Sandbox Code Playgroud)

一个问题是我找不到类型Element的构造函数,所以我无法提供默认值(也许是第一个arg ),所以我不能使用这个方法.

另外,我找不到Element类型的定义.

我还读到,无论如何都要进入一个可能的内部并不是一个好主意,而是通过使用仿函数(如地图或fmap)来解除与它相反的功能.

在这种情况下,我试图调用外部函数,如:

  button <- querySelector (wrap "#btn") doc
  let cn = getClassName button
  log $ "classname=" <> show cn

-- The basic question is how to implement this function?
getClassName :: Maybe HTMLElement -> String
getClassName e = map className  (map fromElement e)
Run Code Online (Sandbox Code Playgroud)

注意:在Web.HTML.HTMLElement中提供了classNamefromElement.

正如你所看到的,我试图通过用地图调用函数来提升函数,因为函数处理Maybes,但我陷入了"Maybe Element"和"Element"之间的类型冲突的困境中"和"HTMLElement"与"元素"等

是的,我承认我在这里遇到了一些问题,这不是一个真正的初学者问题,但它让我感到非常困难,因为获取HTML对象的类名非常简单.当然,我一定错过了什么?

顺便说一句,这是我的HTML:

<!doctype html>
<html>
  <body>
    <script src="index.js"></script>
    <p>
      <input type="button" class="btn-class" value="click me" id="btn"/>
    </p>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

更普遍的问题是:如何深入嵌套两个monad级别的值?

Igo*_*dov 2

实际上,您通过自己调查这个问题做得很好,我只能建议根据您提供的示例进行重构。

假设我们不关心在特定情况下记录失败消息。这意味着,我们可以通过以下方式替换每个此类日志记录pure unit

getBtn ::  Effect Unit
getBtn = do
  log "now in getBtn"
  doc <- map toParentNode (window >>= document)
  mbtn <- querySelector (wrap "#btn") doc
  case mbtn of
    Nothing -> pure unit
    Just btn -> do
      let mhtmlEl = fromElement btn
      case mhtmlEl of
        Nothing -> pure unit
        Just htmlEl -> do
          let cn = className htmlEl
          log $ "classname below:"
          cn >>= log
Run Code Online (Sandbox Code Playgroud)

然后我们可以在这里注意到一个有趣的模式:

case mbtn of
  Nothing -> pure unit
  Just btn -> do
    let mhtmlEl = fromElement btn
Run Code Online (Sandbox Code Playgroud)

即我们想要fromElement对一个值应用函数,btn如果它是 ,Just btn或者如果它是 ,则不执行任何操作Nothing。结果类型必须是Maybe值。

第一个想法是使用mapfunction,但是 的类型fromElementfromElement :: Element -> Maybe HTMLElement,所以结果类型将是Maybe (Maybe a))

不管怎样,我们甚至可以按类型搜索这样的函数,第一个结果是bind(与 相同(>>=))。因此,让我们重构一下(为了清楚起见,将类型指定为注释,但确保这不是必需的):

getBtn ::  Effect Unit
getBtn = do
  log "now in getBtn"
  doc <- map toParentNode (window >>= document)
  mbtn <- querySelector (wrap "#btn") doc

  let mhtmlEl = fromElement =<< mbtn -- Maybe HTMLElement

  case mhtmlEl of
    Nothing -> pure unit
    Just htmlEl -> do
      let cn = className htmlEl
      log $ "classname below:"
      cn >>= log
Run Code Online (Sandbox Code Playgroud)

下一步是减少另一个case表达式。这里使用map(与 相同<$>)就足够了:

getBtn ::  Effect Unit
getBtn = do
  log "now in getBtn"
  doc <- map toParentNode (window >>= document)
  mbtn <- querySelector (wrap "#btn") doc

  let mhtmlEl = (fromElement =<< mbtn) -- Maybe HTMLElement
  let mCn = className <$> mhtmlEl -- Maybe (Effect String)

  case mCn of
      Nothing -> log "no such element"
      Just cn -> do
          log $ "classname below:"
          cn >>= log
Run Code Online (Sandbox Code Playgroud)

函数的结果类型getBtn必须是Effect Unit,因此每个Maybe值的情况都必须在此处处理。我就这样保留它,因为这里发生的事情很清楚。但如果您寻求简洁的表示,则maybe可以在此处应用函数:

getBtn ::  Effect Unit
getBtn = do
  log "now in getBtn"
  doc <- map toParentNode (window >>= document)
  mbtn <- querySelector (wrap "#btn") doc

  let mhtmlEl = (fromElement =<< mbtn) -- Maybe HTMLElement
  let mCn = className <$> mhtmlEl -- Maybe (Effect String)

  maybe (log "no such element") (\cn -> log "classname below:" *> cn >>= log) mCn
Run Code Online (Sandbox Code Playgroud)