html - 如何进入内部 Maybe monad 从纯脚本中的 html 按钮中提取类名?

标签 html purescript

我正在尝试学习 purescript

我在一些 HTML 中有一个按钮,我试图打印它的类名。我正在使用 pulp 构建和浏览器

我使用的函数是querySelector:

import Web.DOM.ParentNode (querySelector)

这会在两个“框”中返回我想要的项目 Element:一个外部 Effect monad 和一个嵌入的 Maybe monad:

> :type querySelector
QuerySelector -> ParentNode -> Effect (Maybe Element)

我的 Effect monad 看起来像:

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

我知道我可以通过在外部 Effect monad 上调用 bind (>>=) 来访问内部 Maybe。我的第一个攻击计划是使用 maybe 函数手动拆箱 Maybe。以下是对简单 Int 执行此操作的方法:

> maybe 0 (\x -> x) $  Just 7
7

对于 Maybe 元素,我认为它看起来像这样:

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

一个问题是我找不到类型Element 的构造函数,所以我无法提供默认值(可能是 的第一个参数),所以我可以'不要用这个方法。

此外,我找不到Element 类型的定义。

我还读到,无论如何,进入 Maybe 内部并不是一个好主意,而是通过使用仿函数(如 map 或 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)

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

如您所见,我试图通过使用映射调用它们来提升函数,因为这些函数处理 Maybes,但我陷入了“Maybe Element”和“Element”以及“HTMLElement”与“Element”等之间的类型冲突。

是的,我承认我在这里遇到了一些问题,这并不是一个真正的初学者问题,但令我恼火的是,像获取 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>

更普遍的问题是:如何获得嵌套两个 monad 层的值?

最佳答案

实际上,您自己调查了这个问题,做得很好,我可以根据您提供的示例建议重构。

假设我们不关心在特定情况下记录失败的消息。这意味着,我们可以用 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

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

case mbtn of
  Nothing -> pure unit
  Just btn -> do
    let mhtmlEl = fromElement btn

即我们要申请 fromElementbtn 上运行如果它的值(value) Just btn如果是 Nothing 则什么都不做.结果类型必须是 Maybe值(value)。

第一个想到的是使用map函数,但类型为 fromElementfromElement :: Element -> Maybe HTMLElement ,因此结果类型将为 Maybe (Maybe a)) .

无论如何,我们甚至可以search这样一个按类型分类的函数,第一个结果是 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

下一步是减少另一个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

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

关于html - 如何进入内部 Maybe monad 从纯脚本中的 html 按钮中提取类名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51781123/

相关文章:

Javascript:动态改变正弦波速度

jquery - 我想在输入复选框上添加一些 css

purescript - 记录类型的默认相等性?

haskell - ReaderT 的 Ask 未正确推导 Monad 类型

html - 文本中心关闭了几个像素

javascript - 上传和删除图像

javascript - "cannot read property length of null"- 谷歌

purescript - 映射同类记录类型

dom - (PureScript) 如何在 Eff 以外的单子(monad)上下文中运行 DOM 事件监听器回调?

purescript - 如何将 Data.Argonaut.Decode 模块与 JSON 和任何字段一起使用?