- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在阅读本教程 http://learnyouahaskell.com/a-fistful-of-monads并偶然发现了这个定义:
type KnightPos = (Int,Int)
moveKnight :: KnightPos -> [KnightPos]
moveKnight (c,r) = do
(c',r') <- [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1)
,(c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2)
]
guard (c' `elem` [1..8] && r' `elem` [1..8])
return (c',r')
in3 :: KnightPos -> [KnightPos]
in3 start = do
first <- moveKnight start
second <- moveKnight first
moveKnight second
in3
的问题(这需要棋盘上的一对坐标 (Int,Int) 并生成一个字段列表 [(Int,Int)] 可以在骑士的 3 次移动中从该字段到达。是否可能(如果是的话 - 如何这样做)将该功能改造成
inNMoves :: (Num a) => KnightPos -> a -> [KnightPos]
以便它还以移动次数作为参数,而不是恰好绑定(bind) 3 次跳跃?
最佳答案
由于这个练习是关于 List Monad 的,尽量不要去想你对 List 的了解,而是将自己限制在 monad 的结构上。所以那将是
move :: Monad m => Pos -> m Pos
move
需要一个
Pos
并给你一些关于
Pos
的东西某些 monadic 上下文中的事物
m
. (在列表的情况下,“上下文”是“任意多重性+排序”。但尽量不要考虑它)。
do
这里只是使用
(>>=)
的语法糖.出于本说明的目的,您需要知道如何使用
(>>=)
将 do 转换为表达式。 .
(>>=)
有签名
m a -> (a -> m b) -> m b
.我们需要的实例是
m Pos -> (Pos -> m Pos) -> m Pos
.你看我们已经实例化了
a
和
b
这里到
Pos
.您也可以识别中间部分
(Pos -> m Pos)
正在
move
在这里签名。所以使用
(>>=)
并给它
move
作为第二个参数,我们可以创建一个
m Pos -> m Pos
类型的函数.
moveM :: Monad m => m Pos -> m Pos
moveM mp = mp >>= move
m Pos -> m Pos
可以按您希望的顺序执行,因为它是从类型到自身的函数(我认为这可以称为 monad 内同态,因为类型是 monad)。
move2M :: Monad m => m Pos -> m Pos
move2M mp = moveM (moveM (mp))
move2M :: Monad m => m Pos -> m Pos
move2M = moveM . moveM
n
参数化的移动次数),我们只需要一些
moveM
s 由函数链操作符
.
连接.所以如果 n 是 3,我们想要
moveM . moveM . moveM
.以下是如何以编程方式执行此操作:
nmoveM :: Monad m => Int -> m Pos -> m Pos
nmoveM n = foldr1 (.) (replicate n moveM) -- n "moveM"s connected by (.)
foldr1
对于
n
的值未定义<= 0. 定义
nmoveM 0
很有意义到“什么都不做”。换句话说,恒等函数,
id
.
nmoveM :: Monad m => Int -> m Pos -> m Pos
nmoveM n = foldr (.) id (replicate n moveM)
foldr
而不是
foldr1
这需要一个额外的“基本案例”,
id
.
m Pos -> m Pos
,但我们想要
Pos -> m Pos
.这意味着,给定
Pos
,我们首先必须将其嵌入上下文
m
,然后执行
nMoveM
.这个嵌入运算符(我认为它可以称为初始代数)是
return
(类型
Monad m => a -> m a
)
nmoves :: Monad m => Int -> Pos -> m Pos
nmoves n = nmoveM n . return
nmoves :: Monad m => Int -> Pos -> m Pos
nmoves n = foldr (.) id (replicate n move) . return
(>>=)
实际上通常有点不干净,因为它是如此不对称:它需要一个
m a
和一个
a -> m b
.换句话说,它有点过于关心转换后的对象,而只关心我们案例的转换。这使得组合转换变得不必要地困难。这就是为什么我们不得不加入
. return
: 这是
Pos
的初始转换至
m Pos
,这样我们就可以自由组合任意数量的
m Pos -> m Pos
.
(>>=)
导致以下模式:
ma >>= f_1 >>= f_2 >>= ... >>= f_n
ma
是 monad 和
f_i
是
a -> m b
类型的“箭头” (通常 a = b)。
(>=>)
,它结合了两个
a -> m b
按序列键入箭头,并返回另一个箭头。
(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
move
实际上是这样一个箭头(
Pos -> m Pos
)。所以
move >=> move >=> move >=> move >=> move
Pos -> m Pos
类型的有效表达式.使用
(>=>)
时,monad 的可组合特性变得更加明显。 .
nmoves
使用
(>=>)
像这样:
nmoves :: Monad m => Int -> Pos -> m Pos
nmoves n = foldr1 (>=>) (replicate n move) -- n "move"s connected by >=>
foldr1
,我们在问“是什么让 0 次连续移动”?它必须是相同的类型,
Pos -> m Pos
,答案是
return
.
nmoves :: Monad m => Int -> Pos -> m Pos
nmoves n = foldr (>=>) return (replicate n move)
nmoves
的定义进行比较在 monad 自同态世界中:代替函数与
(.)
结合使用和基本案例
id
,我们现在将箭头与
(>=>)
结合起来和基本案例
return
.好处是我们不必注入(inject)给定的
Pos
至
m Pos
.
(>=>)
比
(>>=)
干净多了.
关于Haskell 递归以 'do' 表示法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30471253/
在 Haskell 中,类型声明使用双冒号,即 (::),如 not::Bool -> Bool。 但是在许多语法与 Haskell 类似的语言中,例如榆树、 Agda 、他们使用单个冒号(:)来声明
insertST :: StateDecoder -> SomeState -> Update SomeState SomeThing insertST stDecoder st = ... Stat
如果这个问题有点含糊,请提前道歉。这是一些周末白日梦的结果。 借助 Haskell 出色的类型系统,将数学(尤其是代数)结构表达为类型类是非常令人愉快的。我的意思是,看看 numeric-prelud
我有需要每 5 分钟执行一次的小程序。 目前,我有执行该任务的 shell 脚本,但我想通过 CLI 中的键为用户提供无需其他脚本即可运行它的能力。 实现这一目标的最佳方法是什么? 最佳答案 我想你会
RWH 面世已经有一段时间了(将近 3 年)。在在线跟踪这本书的渐进式写作之后,我渴望获得我的副本(我认为这是写书的最佳方式之一。)在所有相当学术性的论文中,作为一个 haskell 学生,读起来多么
一个经典的编程练习是用 Lisp/Scheme 编写一个 Lisp/Scheme 解释器。可以利用完整语言的力量来为该语言的子集生成解释器。 Haskell 有类似的练习吗?我想使用 Haskell
以下摘自' Learn You a Haskell ' 表示 f 在函数中用作“值的类型”。 这是什么意思?即“值的类型”是什么意思? Int 是“值的类型”,对吗?但是 Maybe 不是“值的类型”
现在我正在尝试创建一个基本函数,用于删除句子中的所有空格或逗号。 stringToIntList :: [Char] -> [Char] stringToIntList inpt = [ a | a
我是 Haskell 的新手,对模式匹配有疑问。这是代码的高度简化版本: data Value = MyBool Bool | MyInt Integer codeDuplicate1 :: Valu
如何解释这个表达式? :t (+) (+3) (*100) 自 和 具有相同的优先级并且是左结合的。我认为这与 ((+) (+3)) (*100) 相同.但是,我不知道它的作用。在 Learn
这怎么行 > (* 30) 4 120 但这不是 > * 30 40 error: parse error on input ‘*’ 最佳答案 (* 30) 是一个 section,它仍然将 * 视为
我想创建一个函数,删除满足第二个参数中给定谓词的第一个元素。像这样: removeFirst "abab" ( 'b') = "abab" removeFirst [1,2,3,4] even =
Context : def fib(n): if n aand returns a memoized version of the same function. The trick is t
我明白惰性求值是什么,它是如何工作的以及它有什么优势,但是你能解释一下 Haskell 中什么是严格求值吗?我似乎找不到太多关于它的信息,因为惰性评估是最著名的。 他们各自的优势是什么。什么时候真正使
digits :: Int -> [Int] digits n = reverse (x) where x | n digits 1234 = [3,1,2,4]
我在 F# 中有以下代码(来自一本书) open System.Collections.Generic type Table = abstract Item : 'T -> 'U with ge
我对 Haskell 比较陌生,过去几周一直在尝试学习它,但一直停留在过滤器和谓词上,我希望能得到帮助以帮助理解。 我遇到了一个问题,我有一个元组列表。每个元组包含一个 (songName, song
我是 haskell 的初学者,我试图为埃拉托色尼筛法定义一个简单的函数,但它说错误: • Couldn't match expected type ‘Bool -> Bool’
我是 Haskell 语言的新手,我在使用 read 函数时遇到了一些问题。准确地说,我的理解是: read "8.2" + 3.8 应该返回 12.0,因为我们希望返回与第二个成员相同的类型。我真正
当我尝试使用真实项目来驱动它来学习 Haskell 时,我遇到了以下定义。我不明白每个参数前面的感叹号是什么意思,我的书上好像也没有提到。 data MidiMessage = MidiMessage
我是一名优秀的程序员,十分优秀!