更改使用模式匹配的 do 表达式来应用绑定运算符

2024-04-05

原问题

利亚,在对于更多的 Monad http://learnyouahaskell.com/for-a-few-monads-more显示此功能,

solveRPN :: String -> Maybe Double  
solveRPN st = do  
    [result] <- foldM foldingFunction [] (words st)  
    return result

它结合使用模式匹配do表达确保 monad 出来foldM包装一个单例列表.

为了真正了解事物的本质do的表达以及Monad,我一直在重写那本书中的大多数例子>>= and >>而不是do表达,一种在某处建议的做法现实世界哈斯克尔 http://book.realworldhaskell.org/read/我也有,不过不记得是哪一章了。

对于上面的功能,我有点困惑。不使用 的最简洁的编写方式是什么do表达?我能想到的最好的办法是

solveRPN :: String -> Maybe Double
solveRPN s = foldM step [] (words s) >>= \x -> case x of
                                               [y] -> Just y
                                               _   -> Nothing

但我希望有一些更干净的东西,因为这个噪音很大,原因有两个:

  • 它使用 lambda
  • 它使用case表达式,看起来并不比if-then-else.

这个问题 https://stackoverflow.com/questions/59226842/how-to-pattern-match-an-intermediate-value-in-haskell/59226926#59226926与现在有关。

I asked 另一个问题 https://stackoverflow.com/questions/62803061/can-this-function-be-written-in-point-free-style-if-not-why/这实际上强调了这一问题的基本问题:

我该如何拉动head在列表之外并且仅对单例列表成功?

这与Maybe将结果包装在solveRPN.

Update

The 我在那里接受的答案 https://stackoverflow.com/a/62803320/5825294针对上述问题提出了明确的解决方案:

func :: [a] -> a
func = foldr1 (const (const undefined))

可以用来轻松书写solveRPN以无点风格:

solveRPN :: String -> Maybe Double
solveRPN st = foldM foldingFunction [] (words st) >>= Just . foldr1 (const (const undefined))

然而,这绝对不能令人满意,因为它没有充分利用Maybemonad,在运行时失败而不是返回Nothing当输出不正确时。

我认为,玩弄这个可能会让我或其他人回答我最初的问题,而无需do/case/帮手。


The 脱糖do符号 https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-470003.14Haskell 报告中指定的实际上包含一个模式匹配,以便处理模式匹配失败fail,现在指定在MonadFail类型类。它可以写成case或作为一个函数。

do {e}                 =  e
do {e;stmts}           =  e >> do {stmts}
do {p <- e; stmts}     =  let ok p = do {stmts}
                              ok _ = fail "..."
                            in e >>= ok
do {let decls; stmts}  =  let decls in do {stmts}

所以在你的例子中,可能看起来像这样。

solveRPN :: String -> Maybe Double  
solveRPN st = foldM foldingFunction [] (words st) >>= \ x -> case x of
    [result] -> return result
    _ -> fail "Pattern match failure in do expression at file:line:col"

(而且当然fail message :: Maybe a只是Nothing.)

您可以使用以下命令使其更加简洁LambdaCase以避免额外的变量。

{-# LANGUAGE LambdaCase #-}

solveRPN :: String -> Maybe Double  
solveRPN st = foldM foldingFunction [] (words st) >>= \ case
    [result] -> return result
    _ -> fail "Pattern match failure in do expression at file:line:col"

这是标准的脱糖,但如果你想进一步解决这个问题,你可以使用辅助函数。标准listToMaybe :: [a] -> Maybe a如果您想允许非单例列表,则可以使用。

import Data.Maybe (listToMaybe)

solveRPN :: String -> Maybe Double  
solveRPN st = foldM foldingFunction [] (words st) >>= listToMaybe

没有标准singletonToMaybe但你可以轻松地写一个。

singletonToMaybe :: [a] -> Maybe a
singletonToMaybe [x] = Just x
singletonToMaybe _   = Nothing

-- or:

singletonToMaybe xs = guard (isSingleton xs) *> listToMaybe xs

isSingleton = null . drop 1

然后使用单子组合运算符以无点风格编写函数<=< or >=>.

solveRPN :: String -> Maybe Double  
solveRPN = singletonToMaybe <=< foldM foldingFunction [] . words
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

更改使用模式匹配的 do 表达式来应用绑定运算符 的相关文章

随机推荐

  • 使用 Python evdev 模拟按住控制器 dpad 按钮

    我正在尝试使用 Python evdev 模拟按住控制器上的 DPad 按钮 到目前为止 我已经成功按下一个按钮 如下所示 import os import time from evdev import uinput ecodes as e
  • Active Records 按 ID 排序[重复]

    这个问题在这里已经有答案了 如果我有 id 为 1 2 3 4 的记录 并且想要以某种方式对它们进行排序 例如 1 4 2 3 我该怎么做 我想类似的东西 但它当然行不通 Service all order id 1 4 2 3 贾斯汀 韦
  • JVM 在 OutOfMemoryError 之后是否自行终止 [重复]

    这个问题在这里已经有答案了 发生 OutOfMemoryError 后 JVM 会自行终止吗 如果不是那么为什么 它会尝试收回资源吗 还是有其他原因 OutOfMemoryError 不会终止 JVM 如果它未被捕获 它将终止引发错误的线程
  • angularjs 获取表单操作并提交给它

    我有一个表单 我想捕获它的提交 检查数据的验证 然后将表单提交到 HTML 表单内的操作 div div
  • Jquery 验证自定义错误消息位置

    这看起来很简单 但我无法弄清楚 我正在使用 jquery 验证插件 我正在尝试验证
  • 从点列表中获取两个最近的点

    我得到了一个整数 浮点数列表 我需要找到最接近的两个数字 我将如何仅使用嵌套 for 循环来做到这一点 如果点是一维的 就像您的输入只是一个数字列表 例如 1 4 6 2 那么你可以通过对它们进行排序并找到差异最小的在 O n log n
  • Reactjs - redux 表单和材质 UI 框架 - 具有自动类型 - 和清除字段功能

    我正在构建一个使用 redux 表单和材料 ui 框架的嵌套表单框架 迄今为止我已经在这里构建了组件 https codesandbox io s heuristic hopper lzekw https codesandbox io s
  • 在 GWT 中使数据网格的行可拖动

    我想制作一个数据网格 其中的行可以拖动 以便人们可以通过拖动行来上下移动行 由于数据网格的行将作为元素获取 我知道如何使小部件可拖动 但是如何使数据网格的行可拖动 我不想使用任何额外的插件或库来实现此目的 我所知道的唯一支持单元格小部件拖放
  • 如何配置 Hibernate 以立即应用所有保存、更新和删除?

    我该如何配置休眠 http www hibernate org 在会话执行每个操作后立即将所有保存 更新和删除应用到数据库服务器 默认情况下 Hibernate 将所有保存 更新和删除操作排入队列 并仅在经过一段时间后才将它们提交到数据库服
  • Scala:列表 [Tuple3] 到映射 [字符串,字符串]

    我得到的查询结果为List Int String Double 我需要将其转换为Map String String 用于在 html 选择列表中显示 我的破解方案是 val prices dao getPricing flatMap cas
  • 使用 Redux Observable 等待操作序列

    我有一个用例 在使用 Redux Observables 调度另一个操作之前 我需要等待一系列操作 我见过一些类似的问题 但我无法理解如何在给定的用例中使用这些方法 本质上我想做这样的事情 action ofType PAGINATION
  • 自定义内存管理器

    我正在尝试实现一个自定义内存管理器 我想知道是否有更好的方法来实现这个函数 因为当我被问及 void 指针算术时 有几个人认为如果我在 C 中有一个 void 那就太糟糕了错误的 allocates a page of memory voi
  • 为什么我的调试数据未格式化?

    var dump and print r使用 Laravel 4 时显示的数据未格式化 如何格式化数据以使其更具可读性 通过在命令行上运行以下命令将 Kint 添加到您的composer json composer require rave
  • Metamask 停止注入 web3.js

    据我们所知 从2020年1月13日开始 metamask将不再注入web3 js 我们应该采取哪些方法来停止对web3的依赖 另外 我们如何使用目前正在注入 web3 js 的现有 Metamask 来测试它 window ethereum
  • 为什么使用类方法而不是静态方法? [复制]

    这个问题在这里已经有答案了 我知道他们是做什么的 并且我见过很多这两个例子 但我还没有找到一个我必须使用的例子classmethod而不是用staticmethod 最常见的例子是classmethod我见过的是用于创建新实例类本身 就像这
  • 积分运算符 quot 与 div

    类型类 Integral 有两个操作quot and div 但在 Haskell 2010 语言报告中并没有具体说明它们应该做什么 假如说div是积分除法 什么quot不同 或者目的是什么quot 什么时候使用其中一个 什么时候使用另一个
  • 生成生成集的算法

    给定此输入 1 2 3 4 我想生成一组跨越集 1 2 3 4 1 2 3 4 1 2 3 4 1 3 2 4 1 2 3 4 1 3 2 4 1 4 2 3 1 2 3 4 1 3 2 4 1 4 2 3 1 2 3 4 1 2 4 3
  • 如何在 django 2.0 管理中使用allow_tags?

    Support for the allow tags attribute on ModelAdmin methods is removed 刚刚找到答案 使用mark safe https docs djangoproject com en
  • 非连续元素的最大和

    给定一个正整数数组 从该数组中查找非连续元素的最有效算法是什么 这些元素加在一起时会产生最大总和 动态规划 给定一个数组A 0 n let M i 是使用带有索引的元素的最佳解决方案0 i Then M 1 0 用于递归 M 0 A 0 a
  • 更改使用模式匹配的 do 表达式来应用绑定运算符

    原问题 利亚 在对于更多的 Monad http learnyouahaskell com for a few monads more显示此功能 solveRPN String gt Maybe Double solveRPN st do