- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑我编写的以下代码:
import Control.Monad
increasing :: Integer -> [Integer]
increasing n
| n == 1 = [1..9]
| otherwise = do let ps = increasing (n - 1)
let last = liftM2 mod ps [10]
let next = liftM2 (*) ps [10]
alternateEndings next last
where alternateEndings xs ys = concat $ zipWith alts xs ys
alts x y = liftM2 (+) [x] [y..9]
其中“increasing n
”应返回一个 n 位数字的列表,其数字从左到右增加(或保持不变)。
有办法简化这个吗? 在我看来,到处使用“let
”和“liftM2
”看起来很难看。我认为我错过了有关列表单子(monad)的一些重要内容,但我似乎无法摆脱它们。
最佳答案
好吧,至liftM
函数 go,我首选的使用方法是 Control.Applicative
中定义的组合器。使用这些,你可以写 last = mod <$> ps <*> [10]
。 ap
来自 Control.Monad
的函数做同样的事情,但我更喜欢中缀版本。
什么(<$>)
和(<*>)
像这样:liftM2
变成一个函数a -> b -> c
进入函数m a -> m b -> m c
。普通liftM
只是 (a -> b) -> (m a -> m b)
,与 fmap
相同还有(<$>)
.
如果对多参数函数执行此操作会发生什么?它变成类似 a -> b -> c -> d
进入m a -> m (b -> c -> d)
。这就是ap
或(<*>)
进来:他们所做的就是把类似 m (a -> b)
进入m a -> m b
。因此,您可以继续按照这种方式串接任意数量的参数。
也就是说,特拉维斯·布朗(Travis Brown)是正确的,在这种情况下,您似乎并不真正需要上述任何内容。事实上,您可以大大简化您的功能:例如, last
和next
可以写为映射到同一列表的单参数函数,ps
,和zipWith
与 zip
相同和一个 map
。所有这些 map 都可以组合起来并插入 alts
功能。这使得alts
单参数函数,消除 zip
以及。最后,concat
可以与 map
结合使用如concatMap
或者,如果愿意,(>>=)
。最终结果如下:
increasing' :: Integer -> [Integer]
increasing' 1 = [1..9]
increasing' n = increasing' (n - 1) >>= alts
where alts x = map ((x * 10) +) [mod x 10..9]
请注意,我为从您的版本获得该版本所做的所有重构纯粹是语法,仅应用不应影响函数结果的转换。等式推理和引用透明性很好!
关于list - Haskell:如何简化或消除 liftM2?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3989353/
在 Haskell 中,(liftM .liftM)、(liftM .liftM .liftM) 等有别名吗? 这样我就不必那么冗长了,例如: (liftM . liftM) (+ 1) [Just
我试图理解下面的表达。它转换字符列表['a','b','c']到字符串列表 ["a", "b", "c"] liftM (:[]) "abc" 这是怎么发生的? 最佳答案 机器猴头运算符(operat
最近我一直在编写在 IO monad 中返回数据结构的 FFI 代码。例如: peek p = Vec3 (#peek aiVector3D, x) p (#peek
replicate 3 "hi" 产生 ["hi", "hi", "hi"] 但是 liftM (replicate 3) "hi" 产生 ["hhh", "iii"] liftM 是如何(精确地)运
monad 和 applicative 的区别在于前者可以根据之前的结果选择下一个计算: (\x -> if x == 1 then (\_ -> []) else (\y -> (\z -> \w
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 2年前关闭。 Improve th
在 Haskell 中使用一元表达式时,使用 liftM的(即使在中缀位置)对我来说通常显得很不美观且冗长。 大多数其他一元基元( >>= 、 >> )甚至 liftM的纯吊坠 $是中缀运算符。这让我
我有以下功能: sendq :: Socket -> B.ByteString -> String -> IO PortNumber -> IO () sendq s datastring host
我对 liftM 如何保留上下文感到困惑,特别是在 Writer monad 的情况下。我一直在阅读“Learn You a Haskell for Great Good”,并且一直停留在它对 lif
根据the Typeclassopedia (以及其他来源),Applicative逻辑上属于 Monad和 Pointed (因此 Functor )在类型类层次结构中,所以如果 Haskell 前
这个问题已经有答案了: What is the monomorphism restriction? (1 个回答) 已关闭 6 年前。 当我在 ghci 中定义此类函数时: > :m Control.
我有 getLinesIn = liftM lines 。 getContents 比 readAndWriteIn = do list m0 String 与实际类型 IO String 匹配
(注意:我使用 Haskell 术语来表达问题;欢迎使用相同的术语和/或范畴论的数学语言来回答,包括我谈到仿函数和单子(monad)定律时的正确数学定义和公理。) 众所周知,每个 monad 也是一个
在 Haskell 中,以下工作: > (+) `liftM` (Just 3) `ap` (Just 5) Just 8 Frege 提示使用括号: frege> (+) `liftM` (Just
如果我有一个采用两个类型参数的 monad 转换器类型,我可以使用 liftM将值提升到转换后的 monad 中: scala> val o = 1.point[List].liftM[OptionT
两个表达式 y >> pure x liftM (const x) y 在 Haskell 中具有相同的类型签名。我很好奇它们是否等价,但我既无法提供事实证明,也无法提供反例。 如果我们重写这两个表达
我是一名优秀的程序员,十分优秀!