Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
OCaml';s GADT作为执行级别的参数_Ocaml_Gadt - Fatal编程技术网

OCaml';s GADT作为执行级别的参数

OCaml';s GADT作为执行级别的参数,ocaml,gadt,Ocaml,Gadt,我试图编写一个函数run,使用一个参数来参数化它的执行级别。我希望此函数在给定级别后返回其输出。我使用GADTs让的输出运行取决于它的输入 代码如下: type _ level_output = | FirstO : int -> int level_out

我试图编写一个函数
run
,使用一个参数来参数化它的执行级别。我希望此函数在给定级别后返回其输出。我使用GADTs让
的输出运行
取决于它的输入

代码如下:

type _ level_output =                                                                                                                   
  | FirstO  : int -> int level_output                                                                                                  
  | SecondO : float -> float level_output                                                                                              
  | ThirdO  : string -> string level_output                                                                                            

type _ run_level_g =                                                                                                                    
  | First  : int run_level_g                                                                                                           
  | Second : float run_level_g                                                                                                         
  | Third  : string run_level_g 

type run_level = Any : 'a run_level_g -> run_level

let first _ =
  (*do stuff*)
  1

let second _ =
  (*do stuff*)
  2.5

let third _ =
  (*do stuff*)
  "third"

let run1 (type a) (level:a run_level_g) data : a level_output =
  let out = first data in
  match level with
  | First -> FirstO out
  | Second ->
    let out = second out in
    SecondO out
  | Third ->
    let out = second out in
    let out = third out in
    ThirdO out


let run2 (type a) (level:a run_level_g) data : a level_output =
  let out = first data in
  if Any level = Any First
  then FirstO out
  else
    let out = second out in
    if Any level = Any Second
    then SecondO out
    else
      let out = third out in
      ThirdO out


type (_,_) eq = Eq : ('a,'a) eq

let eq_level (type a b) (x:a run_level_g) (y:b run_level_g) : (a, b) eq option =
  match x, y with
  | First, First -> Some Eq
  | Second, Second -> Some Eq
  | Third, Third -> Some Eq
  | _ -> None

let cast_output (type a b) (Eq:(a, b) eq) (v:a level_output) : b level_output = v

let run3 (type a) (level:a run_level_g) data : a level_output =
  let out = first data in
  let eq = eq_level First level in
  match eq with
  | Some eq -> cast_output eq (FirstO out)
  | None ->
    let out = second out in
    let eq = eq_level Second level in
    match eq with
    | Some eq -> cast_output eq (SecondO out)
    | None ->
      let out = third out in
      let eq = eq_level Third level in
      match eq with
      | Some eq -> cast_output eq (ThirdO out)
      | None -> failwith "this can't happen"
有三个版本的
run
。第一个很好,但有代码重复,我想删除它。我希望我的函数看起来更像
run2
,但是这个函数没有编译,因为类型检查器无法从if条件推断类型。这个问题的答案是
run3
,但现在我遇到了这个笨重的
failwith
案例,显然不可能发生


我想知道是否有一种方法可以让我做到两全其美,一个没有代码重复和案例失败的函数?

我发现你的函数
run1
是迄今为止可读性最强的函数。 消除一些代码重复的一种可能是使run1递归

首先,可以定义一个简短的辅助函数来从level_输出中提取数据

let proj (type a) (x:a level_output): a = 
  match x with
  | FirstO x -> x
  | SecondO x -> x
  | ThirdO x -> x;;
然后,run的递归变量可以写成

let rec run: type a. a run_level_g -> 'b -> a level_output = 
  fun level data -> match level with 
  | First -> FirstO(first data)
  | Second -> SecondO(second @@ proj @@ run First data)
  | Third -> ThirdO(third @@ proj @@ run Second data);;

但你为什么使用GADT?我的意思是,如果
level\u output
run\u level\u g
只是简单的代数类型,那么您的
run2
就可以工作了。有什么理由使用GADT吗?我不想在我确切知道将返回的类型后,在我使用的每个位置都解包
level_输出
。这将在呼叫位置创建一组
failwith
案例。为什么将
run的声明替换为
let rec run(类型a)(级别:a run\u level\u g)数据:一个level_输出
会导致类型错误?因为
run
函数是递归多态的:它在其定义中被调用,并使用其类型参数的不同实例()。因此,有必要为函数类型添加一个明确的通用量化。这里,
类型a
是一个简短的表示法,它将类型声明为通用量化(对于多态递归)和局部抽象(对于GADT模式匹配的类型细化).您知道有什么方法可以声明
类型a
是通用的量化和局部抽象的,适合于内联类型信息的声明。与用于
proj
而不是
run
的一样,在这种情况下,这实际上是不可能的:通用量化应用于类型表达式,因此您至少需要有
'a'运行级别\u g->\u->'a级别\u输出
,因为您需要表示级别\u输出中的
'a
'a运行级别\u g
中普遍量化的相同。您可以内联地重复类型信息,但我不确定它是否带来很多好处。