我正在尝试研究应用于Swift(一种多范式语言)的函数式编程。我向自己提出的一种练习是尝试做一个声明式的扑克手评估程序。
下面是一些代码摘录和我的问题:
typealias Rule = ([Card]) -> Result
“结果”是一种类型,用于保存当前评估状态(已在等级上评估过的牌,如果最后一次规则评估成功与否,则评估剩余牌数和评估等级)。输入是要评估的阵列(可以是一组)卡。
我还创建了此功能:
func id(_ hand:[Card]) -> Result ...
这将从卡片组中产生最少的结果。
结果还具有一组链接规则评估的功能(在此简化):
func apply(_ rule:Rule) -> Result
func andThen(_ rule:Rule) -> Result
func andAlso(_ rule:Rule) -> Result
func otherwise(_ rule:Rule) -> Result
func continueWith(_ rule:Rule) -> Result
什么使我可以将扑克排名规则声明为:
let fullHouse = { (hand) in
threeOfAKind(hand).andThen(pair)
}
或
let royalStraightFlush = { (hand) in
straightFlush(hand).andAlso(straightAceHigh)
}
并将所有排名规则链接为:
let evaluate = { (hand) in
//id(hand)
royalStraightFlush(hand)
.otherwise(straightFlush)
.otherwise(fourOfAKind)
.otherwise(fullHouse)
.otherwise(flush)
.otherwise(straight)
.otherwise(threeOfAKind)
.otherwise(twoPair)
.otherwise(pair)
.continueWith(highCard) }
Result
,原样:
但是...
它不仅具有一个通用的>> =绑定函数,而且还具有多个特定的函数,它需要R a->(a-> R a)-> R a,它可以链接规则并将卡设置为从先前的部分结果状态进行评估。
(由于已实现)它的通用性不足以代替Card或[Card]处理其他类型。另一方面,我认为相同的链接逻辑可以在其他规则系统上进行一些更改...
我的问题是:Result
是单子吗?否则,为什么不呢?我的两个关注是上面提到的那些。
我认为了解此具体示例上的这些要点(或知道这是其他一些盲点)将使我对monad概念有所了解。
谢谢!
答案 0 :(得分:0)
Monad必须遵守三项Monad法律:
return a >>= f ≡ f a
m >>= return ≡ m
(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
这还意味着为您的monad实现了return
(或等效项)和>>=
(通常称为bind,flatmap等)。Haskell(和其他语言)还添加了map函数(>>
),即使可以根据>>=
来实现。
此外,正如@chepner指出的那样,monad是本身并不是具体类型的抽象。它们是通用的,只能通过类型构造函数实例化。 List
是单子,但是您无法实例化List
。但是,您可以实例化List[Int]
。
如果您想对将单子变成单子的概念有一个很好的了解,请看Brian Beckman的视频Don't Fear the Monad。另外,还有一系列不错的博客文章Monads are Elephants。