gpt4 book ai didi

ocaml - 在 OCaml 中创建 GADT 表达式

转载 作者:行者123 更新时间:2023-12-04 15:10:18 24 4
gpt4 key购买 nike

有我的玩具 GADT 表达式:

type _ expr =
| Num : int -> int expr
| Add : int expr * int expr -> int expr
| Sub : int expr * int expr -> int expr
| Mul : int expr * int expr -> int expr
| Div : int expr * int expr -> int expr
| Lt : int expr * int expr -> bool expr
| Gt : int expr * int expr -> bool expr
| And : bool expr * bool expr -> bool expr
| Or : bool expr * bool expr -> bool expr

评价功能:
let rec eval : type a. a expr -> a = function
| Num n -> n
| Add (a, b) -> (eval a) + (eval b)
| Sub (a, b) -> (eval a) - (eval b)
| Mul (a, b) -> (eval a) * (eval b)
| Div (a, b) -> (eval a) / (eval b)
| Lt (a, b) -> (eval a) < (eval b)
| Gt (a, b) -> (eval a) > (eval b)
| And (a, b) -> (eval a) && (eval b)
| Or (a, b) -> (eval a) || (eval b)

当我们限于 int expr 时,创建表达式是微不足道的:
let create_expr op a b =
match op with
| '+' -> Add (a, b)
| '-' -> Sub (a, b)
| '*' -> Mul (a, b)
| '/' -> Div (a, b)
| _ -> assert false

问题是如何同时支持 int exprbool exprcreate_expr功能。

我的尝试:
type expr' = Int_expr of int expr | Bool_expr of bool expr

let concrete : type a. a expr -> expr' = function
| Num _ as expr -> Int_expr expr
| Add _ as expr -> Int_expr expr
| Sub _ as expr -> Int_expr expr
| Mul _ as expr -> Int_expr expr
| Div _ as expr -> Int_expr expr
| Lt _ as expr -> Bool_expr expr
| Gt _ as expr -> Bool_expr expr
| And _ as expr -> Bool_expr expr
| Or _ as expr -> Bool_expr expr

let create_expr (type a) op (a:a expr) (b:a expr) : a expr =
match op, concrete a, concrete b with
| '+', Int_expr a, Int_expr b -> Add (a, b)
| '-', Int_expr a, Int_expr b -> Sub (a, b)
| '*', Int_expr a, Int_expr b -> Mul (a, b)
| '/', Int_expr a, Int_expr b -> Div (a, b)
| '<', Int_expr a, Int_expr b -> Lt (a, b)
| '>', Int_expr a, Int_expr b -> Gt (a, b)
| '&', Bool_expr a, Bool_expr b -> And (a, b)
| '|', Bool_expr a, Bool_expr b -> Or (a, b)
| _ -> assert false

它仍然无法返回通用类型的值。

Error: This expression has type int expr but an expression was expected of type a expr Type int is not compatible with type a



更新

感谢@gsg,我能够实现类型安全的评估器。两个技巧在那里至关重要:
  • 存在包装Any
  • 类型标记( TyIntTyBool )让我们可以模式匹配 Any类型


  • type _ ty =
    | TyInt : int ty
    | TyBool : bool ty

    type any_expr = Any : 'a ty * 'a expr -> any_expr

    let create_expr op a b =
    match op, a, b with
    | '+', Any (TyInt, a), Any (TyInt, b) -> Any (TyInt, Add (a, b))
    | '-', Any (TyInt, a), Any (TyInt, b) -> Any (TyInt, Sub (a, b))
    | '*', Any (TyInt, a), Any (TyInt, b) -> Any (TyInt, Mul (a, b))
    | '/', Any (TyInt, a), Any (TyInt, b) -> Any (TyInt, Div (a, b))
    | '<', Any (TyInt, a), Any (TyInt, b) -> Any (TyBool, Lt (a, b))
    | '>', Any (TyInt, a), Any (TyInt, b) -> Any (TyBool, Gt (a, b))
    | '&', Any (TyBool, a), Any (TyBool, b) -> Any (TyBool, And (a, b))
    | '|', Any (TyBool, a), Any (TyBool, b) -> Any (TyBool, Or (a, b))
    | _, _, _ -> assert false

    let eval_any : any_expr -> [> `Int of int | `Bool of bool] = function
    | Any (TyInt, expr) -> `Int (eval expr)
    | Any (TyBool, expr) -> `Bool (eval expr)

    最佳答案

    正如您所发现的,这种方法不进行类型检查。它还有一个更基本的问题:GADT 可以是递归的,在这种情况下,枚举它们的情况是完全不可能的。

    相反,您可以将类型具体化为 GADT 并传递它们。这是一个缩减示例:

    type _ expr =
    | Num : int -> int expr
    | Add : int expr * int expr -> int expr
    | Lt : int expr * int expr -> bool expr
    | And : bool expr * bool expr -> bool expr

    type _ ty =
    | TyInt : int ty
    | TyBool : bool ty

    let bin_op (type a) (type b) op (l : a expr) (r : a expr) (arg_ty : a ty) (ret_ty : b ty) : b expr =
    match op, arg_ty, ret_ty with
    | '+', TyInt, TyInt -> Add (l, r)
    | '<', TyInt, TyBool -> Lt (l, r)
    | '&', TyBool, TyBool -> And (l, r)
    | _, _, _ -> assert false

    在某些时候,您会想要一个可以是“任何表达式”的值。引入一个存在性包装器可以实现这一点。 Cheesy 示例:生成随机表达式树:
    type any_expr = Any : _ expr -> any_expr

    let rec random_int_expr () =
    if Random.bool () then Num (Random.int max_int)
    else Add (random_int_expr (), random_int_expr ())

    let rec random_bool_expr () =
    if Random.bool () then Lt (Num (Random.int max_int), Num (Random.int max_int))
    else And (random_bool_expr (), random_bool_expr ())

    let random_expr () =
    if Random.bool () then Any (random_int_expr ())
    else Any (random_bool_expr ())

    关于ocaml - 在 OCaml 中创建 GADT 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30429552/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com