我正在尝试为这个语法编写一个具体的语法(来自Grammatical Framework: Programming with Multilingual Grammars的第 6 章):
abstract Arithm = {
flags startcat = Prop ;
cat
Prop ; -- proposition
Nat ; -- natural number
fun
Zero : Nat ; -- 0
Succ : Nat -> Nat ; -- the successor of x
Even : Nat -> Prop ; -- x is even
And : Prop -> Prop -> Prop ; -- A and B
}
Int
整数、浮点数和字符串字面量(Float
和)有预定义的类别,String
它们可以用作函数的参数,但它们可能不是任何函数的值类型。
此外,它们不能用作线性化类型中的字段。这就是我想做的,使用plus
Predef.gf 中定义的:
concrete ArithmEng of Arithm =
open Predef, SymbolicEng, SyntaxEng, ParadigmsEng in
lincat
Prop = S ;
Nat = {s : NP ; n : Int} ;
lin
Zero = mkNat 0 ;
Succ nat = let n' : Int = Predef.plus nat.n 1 in mkNat n' ;
Even nat = mkS (mkCl nat.s (mkA "even")) ;
And p q = mkS and_Conj p q ;
oper
mkNat : Int -> Nat ;
mkNat int = lin Nat {s = symb int ; n = int} ;
} ;
但当然,这不起作用:我收到错误“线性化类型字段不能是 Int”。
也许我的问题的正确答案是使用另一种编程语言,但我很好奇,因为这个例子在 GF 书中作为练习留给读者,所以我希望它是可以解决的。
我可以使用以下类别编写一元解决Digits
方案Numeral.gf
:
concrete ArithmEng of Arithm =
open SyntaxEng, ParadigmsEng, NumeralEng, SymbolicEng, Prelude in {
lincat
Prop = S ;
Nat = {s : NP ; d : Digits ; isZero : Bool} ;
lin
Zero = {s = mkNP (mkN "zero") ; d = IDig D_0 ; isZero = True} ;
Succ nat = case nat.isZero of {
True => mkNat (IDig D_1) ;
False => mkNat (IIDig D_1 nat.d) } ;
Even nat = mkS (mkCl nat.s (mkA "even")) ;
And p q = mkS and_Conj p q ;
oper
mkNat : Digits -> Nat ;
mkNat digs = lin Nat {s = symb (mkN "number") digs ; d = digs ; isZero = False} ;
} ;
这会产生以下结果:
Arithm> l -bind Even Zero
zero is even
0 msec
Arithm> l -bind Even (Succ Zero)
number 1 is even
0 msec
Arithm> l -bind Even (Succ (Succ (Succ Zero)))
number 111 is even
这当然是一个可能的答案,但我怀疑这不是该练习的解决方式。所以我想知道我是否遗漏了什么,或者 GF 语言是否曾经支持对 Ints 的更多操作?