我们可以在Scala中编码自然数的加法和乘法。但是,是否可以在类型级别上减去两个自然数?
我在Scala中半复制了以下自然数编码:
sealed trait Natural {
type Plus[That <: Natural] <: Natural
}
case object Zero extends Natural {
override type Plus[That <: Natural] = That
}
case class Suc[Prev <: Natural](n: Prev) extends Natural {
override type Plus[That <: Natural] = Suc[Prev#Plus[That]]
}
然后我自己添加乘法:
sealed trait Natural {
type Plus[That <: Natural] <: Natural
type Mult[That <: Natural] <: Natural
}
case object Zero extends Natural {
override type Plus[That <: Natural] = That
override type Mult[That <: Natural] = Zero.type
}
case class Suc[Prev <: Natural](n: Prev) extends Natural {
override type Plus[That <: Natural] = Suc[Prev#Plus[That]]
override type Mult[That <: Natural] = (Prev#Mult[That])#Plus[That]
}
似乎与后来发现的其他实现是一致的,并且可以正常工作:
implicitly[Nat5#Mult[Nat2] =:= Nat10]
implicitly[Nat4#Mult[Nat4] =:= Nat8#Mult[Nat2]]
在过去的几个小时中,我一直在尝试实现减法。
通过以下方法,如果您减去的一个数字(b
中的a - b
)是一个奇数,我似乎可以正确地减去两个数字:
sealed trait Natural {
type Previous <: Natural
type Minus[That <: Natural] <: Natural
}
case object Zero extends Natural {
override type Previous = Zero.type
override type Minus[That <: Natural] = That
}
case class Suc[Prev <: Natural](n: Prev) extends Natural {
override type Previous = Prev
override type Minus[That <: Natural] = (That#Previous)#Minus[Prev]
}
以上内容利用了(N - M) = (N - 1) - (M - 1)
这一事实。最终,递归步骤M
将命中Zero.type
,并返回相应的递归步骤N
。
实际上,请注意,我的实现在给定步骤中转换为(N - M) = (M - 1) - (N - 1)
。因为减法不是可交换的,所以这是不正确的。但是,由于此“交换”发生在每个递归步骤中,因此,如果要减去的数字为奇数,则它会取消。如果它是一个偶数,那么此实现将关闭一个。特别是,它比正确的数字小1:
implicitly[Nat10#Minus[Nat3] =:= Nat7] // Compiles
implicitly[Nat9#Minus[Nat3] =:= Nat6] // Compiles
implicitly[Nat8#Minus[Nat3] =:= Nat5] // Compiles
implicitly[Nat10#Minus[Nat2] =:= Nat8] // Does not compile, while:
implicitly[Nat10#Minus[Nat2] =:= Nat7] // Compiles
implicitly[Nat5#Minus[Nat2] =:= Nat3] // Does not compile, while:
implicitly[Nat5#Minus[Nat2] =:= Nat2] // Compiles
要了解原因,请在纸上进行尝试,其中{/ {1}}用于奇数/正确的情况,m = Suc[Zero.type] (Nat1)
用于错误的情况。无论哪种情况,数字m = Suc[Suc[Zero.type]] (Nat2)
(如n
都不重要)
无论如何,我确实觉得使用这种方法可能会走上正轨,但我被困住了。
p.s。我不担心n - m
中的m > n
会发生什么。
用于完整介绍示例的有用信息:
n - m
答案 0 :(得分:3)
由于减法的递归定义与第二个参数匹配,因此您可以定义:
sealed trait Natural {
type ThisType <: Natural
type Previous <: Natural
type Minus[That <: Natural] = That#SubtractThis[ThisType]
type SubtractThis[That <: Natural] <: Natural
}
case object Zero extends Natural {
type ThisType = Zero.type
type Previous = Zero.type
type SubtractThis[That <: Natural] = That
}
case class Suc[Prev <: Natural](n: Prev) extends Natural {
type ThisType = Suc[Prev]
type Previous = Prev
type SubtractThis[That <: Natural] = Previous#SubtractThis[That#Previous]
}