2017-01-22 25 views
1

Я пытаюсь скомпилировать следующий код с помощью ocamlc.Обобщение типа переменных OCaml

type 'a splitter = {name: string; decision_function : 'a -> bool} 

let splitter12a = {name="x1>x2"; decision_function=(fun x -> x.(1)>x.(2))};; 

let generate_splitter i j = {name="x"^string_of_int(i)^">x"^string_of_int(j); decision_function=(fun x -> x.(i) > x.(j))} ;; 

let splitter12 = generate_splitter 1 2;; 

Однако компилятор жалуется:

File "error.ml", line 7, characters 17-38: 
Error: The type of this expression, '_a array splitter, 
     contains type variables that cannot be generalized 

Я не понимаю, почему я могу объявить специализированный splitter12a тогда generate_splitter не может создавать специализированные разветвители.

ответ

1

Вы столкнулись с так называемым значением. Для пояснения см., Например, раздел того же названия в this chapter Real World Ocaml.

Edit: Обычная работа вокруг (возможно, предложил в этой главе) является расширение ета, намереваясь расширить одну лямбда, например, путем поворота определение let f = g a в let f x = g a x. Но это не относится к вашему делу, потому что RHS вашего def не приводит к функции. На самом деле нет прямого обходного пути для того, что вы хотите сделать.

Один из способов превращают его в функтор:

module MakeSplitter (X : sig val i : int val j : int end) = 
struct 
    let splitter = {name = "x"^string_of_int(i)^">x"^string_of_int(j); decision_function = fun x -> x.(i) > x.(j)} 
end 

module Splitter12 = MakeSplitter(struct val i = 1 val j = 2 end) 
let splitter12 = Splitter12.splitter 

Другим способом будет использовать вспомогательный тип записи с полиморфным полем, очень похожим на выше структуру.

+0

Спасибо! Какое самое достойное решение? Я не знаком с расширением «eta» и специализирующем сплиттер (обходной путь, который я использую сейчас) не является жизнеспособным решением. – RUser4512

+0

В действительности нет прямого обходного пути, но см. Мое редактирование. –