gpt4 book ai didi

Haskell:单子(monad)的单子(monad)

转载 作者:行者123 更新时间:2023-12-02 19:07:37 24 4
gpt4 key购买 nike

我正在学习一些 Haskell,我在使用这些 Monad 时遇到了一些麻烦,我了解它们并知道它们的含义,但在这种特殊情况下我遇到了一些问题。在 LYAH 上学习时,我遇到了一个练习,该练习是关于计算一个骑士在 3 个 Action 中可以到达的位置(来自国际象棋游戏),我们使用了这样的列表单子(monad):

假设,

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')

这是有效的,如果我将我的位置赋予这个函数,它会成功计算 future 可能的位置,但现在我希望在其中实现 Writer monad,这样我就可以检索我是如何到达这一点的。所以我做了这个功能,

假设,

type KnightRoute = Writer [KnightPos] KnightPos

moveKnight' :: KnightPos -> [KnightRoute]
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 $ toKr (c',r') (c,r)
where toKr pos oldpos = Writer (pos,[oldpos])

如果我给它一个 KnightPos 它就可以工作,但使用 monad 我无法从 KnightRoute 中提取 KnightPos 来执行另一个函数时间...

*Main> let a = moveKnight' (2,4) !! 0
*Main> runWriter a
((4,3),[(2,4)])
*Main> a >>= moveKnight'

<interactive>:4:7:
Couldn't match type ‘[]’ with ‘Writer [KnightPos]’
Expected type: KnightPos -> Writer [KnightPos] KnightRoute
Actual type: KnightPos -> [KnightRoute]
In the second argument of ‘(>>=)’, namely ‘moveKnight'’
In the expression: a >>= moveKnight'

我明白为什么它不起作用,我从 Writer 中提取了 (4,3),然后将其交给 KnightPos'。但是 KnightPos' 返回一个 KnightRoute 列表,我需要一个 KnightRoute,这是一个逻辑错误,但我不知道该怎么做。有没有一种简单的方法可以用 Monad 来做到这一点?

提前致谢:)

最佳答案

这种“两个 monad 的组合”在 Haskell 中是极其常见的事情。幸运的是,该语言足够灵活,我们可以很好地对此进行抽象。

从数学上来说,你想要的是 composition of two functors 。这通常用变压器的概念来表达,而不是那种新类型:不是直接使用 Writer monad,而是使用 WriterT monad 变压器。 WriterT w [] abasically the same作为 [Writer w a],所以在您的情况下您可以使用:

import Control.Monad.Trans.Class
import Control.Monad.Trans.Writer

moveKnight'' :: KnightPos -> WriterT [] [KnightPos] KnightPos
moveKnight'' (c,r) = do
(c',r') <- lift [(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])
tell [(c,r)]
return (c',r')

关于Haskell:单子(monad)的单子(monad),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32050222/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com