【发布时间】:2018-12-05 06:36:11
【问题描述】:
我正在尝试研究应用于 Swift(一种多范式语言)的函数式编程。我向自己提议的一个练习是尝试做一个声明式扑克手评估器。
下面是一些代码摘录和我最后的问题:
typealias Rule = ([Card]) -> Result
其中 Result 是一种保存当前评估状态的类型(已经评估过排名的卡片、剩余的卡片、最后一个规则评估是否成功以及评估的排名)。输入是要评估的数组(可能是一组)卡片。
我也创建了这个函数:
func id(_ hand:[Card]) -> Result ...
从卡组中创建一个最小结果。
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,原样:
- 将类型 ([Card]) 包含在更广泛的上下文 (R a) 中
- 有一个 id(结果)函数,可以将 a 类型的对象放入最小的“结果”上下文 (a -> R a)
但是……
它不仅有一个通用的 >>= 绑定函数,还有几个特定的函数,它们需要 R a -> (a -> R a) -> R a 可以链接规则并将卡片设置为从之前的部分结果状态进行评估。
它(在实现时)不够通用,无法处理其他类型,而不是 Card 或 [Card]。另一方面,我认为可以在其他规则系统上使用相同的链接逻辑,并进行一些更改...
我的问题是:Result 是单子吗?否则,为什么不呢?我的两个担忧是上面提到的。
我认为在这个具体示例中理解这些点(或知道这是一些其他盲点)将对我来说一点点单子概念。
谢谢!
【问题讨论】:
-
Monads 是围绕类型 constructors 构建的,而不是类型。例如,在 Haskell 中,
[Int]不是 monad,但[]是,因为您可以定义return :: a -> [a]和(>>=) :: [a] -> (a -> [b]) -> [b]。所以严格来说,Result可能不是单子。 -
Result除了应用规则的布尔结果之外还实现了什么?请注意,您的fullHouse规则并未说明它将如何处理三类和一对不能重叠的要求。 -
谢谢!它保留了两个额外信息:尚未评估的卡片子集(例如:三类规则的剩余两张卡片,帽子可能或不可能是对子)和找到的等级(例如:三同类,一张更高的牌和另一张可以用来比较手牌的牌)。还有一个布尔值来链接规则...
-
好的,那么我想像
type Result v = State HandInfo v和andThen :: Rule -> Bool -> ResultBool这样的东西,所以fullHouse h = threeOfAKind h >>= andThen pair和evaluate h = royalFlush >>= otherwise straightFlush >>= ... >>= otherwise pair >>= otherwise highCard。andThen、otherWise等。与其绑定函数不如工厂创建与>>=绑定的函数。 -
我想我没有得到最后一个,chepner...
标签: swift haskell functional-programming monads