Czy typy nieskończone (aka typy rekurencyjne) nie są możliwe w F #?

Rozmawiałem zSadek Drobi na twitterze, gdy pojawi się informacja, że ​​F # nie obsługuje typów nieskończonych. Okazuje się, że w języku C # możesz zrobić coś w ten sposób:

delegate RecDelegate<T> RecDelegate<T>(T x);

Jednak po kilku eksperymentach na obu naszych częściach ustaliliśmy, że to samo w F # wydaje się niemożliwe zarówno w sposób ukryty, jak i jawny.

Wyraźny:

type 'a specialF = 'a->specialF<'a>

błąd FS0191: Ta definicja typu obejmuje natychmiastowe cykliczne odniesienie poprzez skrót, pole struktury lub relację dziedziczenia.

Domniemany:

let rec specialF (x: 'a) = specialF

Niezgodność typu. Oczekiwano a 'b, ale podano „a ->” b. Wynikowy typ byłby nieskończony przy jednoczeniu '' b 'i' 'a ->' b '.

Oczywiście są to celowo proste próbki.

Zastanawiałem się, czy w jakiś sposób się mylę. Może brakowało mi jakiegoś rodzaju adnotacji?

 Brian05 sie 2009, 19:58
Czy istnieje tutaj praktyczne zastosowanie, czy też pytanie dotyczyło tylko wyników dochodzenia dla zabawy?
 Rick Minerich06 sie 2009, 19:41
O ile mi wiadomo, nie ma praktycznych, przezroczystych aplikacji. Jednak jednym z przykładów może być to, że przy jakimś rodzaju zamkniętego stanu zmiennego może to być przydatne do wielokrotnych zastosowań. ex: add (1) (2) (3) (4) - gdzie można wykonać dowolną liczbę aplikacji.
 Jon Harrop27 gru 2012, 19:13
Oto napisany przeze mnie program OCaml, który używa tej funkcji, aby uniknąć poziomu przekierowania za pomocą rectypes.ffconsultancy.com/languages/ray_tracer/code/1/ray.ml

questionAnswers(3)

QuestionSolution

Możesz też zrobić coś takiego

type 'a RecType = RecType of ('a -> 'a RecType)

aby utworzyć nazwany typ, za pomocą którego można przeprowadzić rekursję. Teraz to działa:

let rec specialF = RecType (fun _ -> specialF)
 Thomas Danecker10 sie 2009, 08:31
Byłbym również zainteresowany, jeśli bardziej ogólna wersja działa:stackoverflow.com/questions/1253374/…
type d<'T> = delegate of 'T -> d<'T>  //'
let del : d<int> = null
let anotherDel = del.Invoke(1).Invoke(2).Invoke(3)

Myślę, że potrzebujesz nazwanego typu, który jest reprezentowany bezpośrednio w CLI, aby przerwać rekursję, więc w F # oznacza to, że potrzebujesz również rzeczywistego typu delegata.

Rekurencyjne typy rekordów również powinny działać.

type A = { A : A }
let rec a : A = { A = a }

Byłbym zainteresowany praktycznym zastosowaniem. Albo nawet niepraktyczny :)

yourAnswerToTheQuestion