2016-05-25 2 views
2

Я пытаюсь построить последовательность рекурсивных модулей в ocaml. Вот минимально простой пример:Связывание типа OCaml в рекурсивных модулях

module rec Foo : sig 
    type t = 
     | A of int 
     | B of Foo.t 
    end = struct 
    type t = 
     | A of int 
     | B of Foo.t 
    end  

    module rec Bar : sig 
    open Foo 
    type map_t = int -> Foo.t 
    type t = { foo : map_t } 
    val bar_of_foo : Foo.t -> t 
    end = struct 
    open Foo 

    let rec bar_of_foo f = match f with 
     | A a -> let ff (_:int) = a in 
       { Bar.foo = ff } 
     | B b -> { foo = bar_of_foo b.foo } 
    end 

Компиляция проваливается в функции bar_of_foo, в матче А с Error: unbound type constructor f.

Я не понимаю, почему это происходит - поле foo определяется как имеющий тип map_t = int -> Foo.t и f имеет подпись int -> Foo.t.

Я также попытался просто ссылаясь на поля записи foo в foo, а не Bar.foo (в случае соответствия для B - что дает мне Errror: unbound record field foo ошибку).

Любые указания или рекомендации с благодарностью получены.

Стив

+0

(1) Внутренний 'f' (внешний' f' является параметром для 'bar_of_foo') имеет подпись' Int -> int', так как он использует 'а: Int 'как возвращаемое значение. Я думаю, что это хорошая идея, чтобы удалить столкновение имен. (2) Я не вижу рекурсивных зависимостей между 'Foo' и' Bar'. Я просто вижу, что 'Bar' использует' Foo', но не наоборот. –

+0

Спасибо Антон. Название столкновения удалено в сообщении. –

+0

ОК, поэтому я не понимаю, как печатает текст в 'bar_of_foo'. Первая строка: '| A a -> let ff (_: int) = a в {Bar.foo = ff} ' начинается с сопоставления с типом' A' (= 'Foo.A'). И тип 'Foo.A' -' int'. Поэтому я понимаю, почему подпись 'ff' является' int -> int'. Но A является одним из вариантов 'Foo.t', поэтому почему' bar_of_foo' не имеет подписи 'Foo.t -> int'? –

ответ

2
  1. С bar_of_foo является функцией, которая имеет тип x -> y.
  2. Алгоритм вывода типа видит, что ваш шаблон соответствует аргументу f на конструкторах Foo.t. Этот факт фиксирует x = Foo.t.
  3. Когда вы возвращаете {foo = ...}, система получает y = Bar.t (или просто t в нашем контексте).
  4. Итак, bar_of_foo : Foo.t -> Bar.t.

Следующий код компилирует и он похож на код в OP:

module Foo : sig 
    type t = 
    | A of int 
    | B of t 
    end = struct 
    type t = 
     | A of int 
     | B of t 
    end 

module Bar : sig 
    type map_t = int -> Foo.t 
    type t = { foo : map_t } 
    val bar_of_foo : Foo.t -> t 
    end = struct 
    open Foo 

    type map_t = int -> Foo.t 
    type t = { foo : map_t } 

    let rec bar_of_foo f = match f with 
     | A a -> { foo = fun (_:int) -> A a } 
     | B b -> bar_of_foo b 
    end 

Тест:

open Foo 
open Bar 

let() = 
    let bar = bar_of_foo (B (B (B (A 42)))) in 
    match (bar.foo 0) with 
    | A n -> print_int n; print_newline() 
    | B _ -> print_string "Impossible!\n" 

И выход:

$ ocaml example.ml 
$ 42 

Примечание что модули Foo и Bar не являются взаимно-рекурсивными. В противном случае мы должны были бы написать

module rec Foo : sig 
    ... 
    end = struct 
    ... 
    end 
and Bar : sig 
    ... 
    end = struct 
    ... 
    end 
+0

Ha! Я, в конце концов, сам справился сам, и был в середине ответа на свой вопрос, когда ты тоже меня избил. Большое спасибо за вашу помощь - вы и camlpost помогли мне туда добраться :-) –

+0

И очень приятная четкая экспозиция типа рассуждений :-) –

0

Этот ответ теперь избыточно, так как вещи указывали здесь отражаются на вопрос.

Синтаксические ошибки в ваших выражениях записи. Использовать = не :, то есть { Bar.foo = f } и { foo = bar_of_foo b }.

После этого у вашего кода все еще возникают проблемы с вводом текста. Например, bar_of_foo b имеет тип t, поэтому он не может использоваться как foo член t.

+0

Спасибо camlspotter. Синтаксическая ошибка удалена в сообщении –

 Смежные вопросы

  • Нет связанных вопросов^_^