在OCaml中使用类型级算术,很容易定义一个nat高于特定值的函数:
let f : 'a succ nat -> string = function _ -> "hej"
f Zero (* <-- Won't compile, argument must be > 0 *)
有没有办法让函数接受“最多”一个值或一个间隔,如0&lt; n&lt; 10?
顺便说一下,这是类型定义:
type z = Z
type 'n succ = S of 'n
type ( 'n) nat =
| Zero : ( z) nat
| Succ : ( 'n) nat -> ( 'n succ) nat
答案 0 :(得分:3)
一种可能性是使用多态变体。
let g : [`A0 of z nat | `A1 of (z succ) nat ] -> string = function
_ -> "hej"
它绝对不像你的例子那么漂亮,但如果你能承受语法负担,它就相当灵活。
答案 1 :(得分:2)
以下怎么样?
通过使用开放的多态变体,我们可以编写一个只能应用于1,3和4的函数。为非常大的数字编写约束显然是非常笨拙的。
首先,让我们定义我们的nat
类型和数字1到5:
# type _ nat =
Zero : [> `Zero] nat
| Succ : 'a nat -> [> `Succ of 'a] nat;;
type _ nat = Zero : [> `Zero ] nat | Succ : 'a nat -> [> `Succ of 'a ] nat
# let one = Succ Zero;;
val one : [> `Succ of [> `Zero ] ] nat = Succ Zero
# let two = Succ one;;
val two : [> `Succ of [> `Succ of [> `Zero ] ] ] nat = Succ (Succ Zero)
# let three = Succ two;;
val three : [> `Succ of [> `Succ of [> `Succ of [> `Zero ] ] ] ] nat =
Succ (Succ (Succ Zero))
# let four = Succ three;;
val four :
[> `Succ of [> `Succ of [> `Succ of [> `Succ of [> `Zero ] ] ] ] ] nat =
Succ (Succ (Succ (Succ Zero)))
# let five = Succ four;;
val five :
[> `Succ of
[> `Succ of [> `Succ of [> `Succ of [> `Succ of [> `Zero ] ] ] ] ] ]
nat = Succ (Succ (Succ (Succ (Succ Zero))))
现在让我们定义一些表示我们限制的类型:
# type 'a no = [`Succ of 'a];;
type 'a no = [ `Succ of 'a ]
# type 'a yes = [ `Succ of 'a | `Zero ];;
type 'a yes = [ `Succ of 'a | `Zero ]
# type last = [ `Zero ];;
type last = [ `Zero ]
使用这些类型,我们可以将1,3或4的数字表示为(last yes no yes no) nat
。此处no
表示不允许此号码,而yes
和last
表示允许此号码。请注意,我们从右侧算起。
现在我们可以定义我们的功能了。请注意,我们只需要在函数域中包含数字的个案:
# let f (x : (last yes no yes no) nat) =
match x with
Succ Zero -> "1"
| Succ (Succ (Succ Zero)) -> "3"
| Succ (Succ (Succ (Succ Zero))) -> "4";;
val f : last yes no yes no nat -> string = <fun>
最后,我们可以尝试使用数字1到5的函数,为不正确的用法获取一些很好的大错误消息:
# f Zero;;
Characters 2-6:
f Zero;;
^^^^
Error: This expression has type ([> `Zero ] as 'a) nat
but an expression was expected of type last yes no yes no nat
Type 'a is not compatible with type
last yes no yes no = [ `Succ of last yes no yes ]
The second variant type does not allow tag(s) `Zero
# f one;;
- : string = "1"
# f two;;
Characters 2-5:
f two;;
^^^
Error: This expression has type
([> `Succ of [> `Succ of [> `Zero ] as 'c ] as 'b ] as 'a) nat
but an expression was expected of type last yes no yes no nat
Type 'a is not compatible with type
last yes no yes no = [ `Succ of last yes no yes ]
Type 'b is not compatible with type
last yes no yes = [ `Succ of last yes no | `Zero ]
Type 'c is not compatible with type
last yes no = [ `Succ of last yes ]
The second variant type does not allow tag(s) `Zero
# f three;;
- : string = "3"
# f four;;
- : string = "4"
# f five;;
Characters 2-6:
f five;;
^^^^
Error: This expression has type
([> `Succ of
[> `Succ of
[> `Succ of
[> `Succ of [> `Succ of [> `Zero ] ] as 'e ] as 'd ]
as 'c ]
as 'b ]
as 'a)
nat
but an expression was expected of type last yes no yes no nat
Type 'a is not compatible with type
last yes no yes no = [ `Succ of last yes no yes ]
Type 'b is not compatible with type
last yes no yes = [ `Succ of last yes no | `Zero ]
Type 'c is not compatible with type
last yes no = [ `Succ of last yes ]
Type 'd is not compatible with type
last yes = [ `Succ of last | `Zero ]
Type 'e is not compatible with type last = [ `Zero ]
The second variant type does not allow tag(s) `Succ