Funkcja ML typu „a ->” b


19

Nasz profesor poprosił nas o przemyślenie funkcji w OCaml, która ma ten typ

'a -> 'b

tj. funkcja jednego argumentu, który może być czymkolwiek, i który może zwrócić coś innego.

Myślałem o użyciu raisefunkcji, która ignoruje jej argument:

let f x = raise Exit

Ale profesor powiedział, że istnieje rozwiązanie, które nie wymaga żadnej funkcji w standardowej bibliotece. Jestem zdezorientowany: jak możesz to zrobić, 'bjeśli go nie masz?

Pytam tutaj, a nie na temat Przepełnienia stosu, ponieważ chcę zrozumieć, co się dzieje, nie chcę po prostu zobaczyć programu bez wyjaśnienia.


2
Prosimy o skierowanie odpowiedzi na uczącego się programowania CS101 w swojej odpowiedzi, a nie na teoretyka typów, który może zainspirować go do odpowiedzi.
Gilles „SO- przestań być zły”

Byłoby to pomocne, gdybyś wyjaśnił, jak wymyśliłeś, że raiseto zadziała, więc wiemy, jak najlepiej wyjaśnić, dlaczego rozwiązanie, którego szuka twój profesor (które zadziała z tych samych powodów, które raisedziała) działa.
sepp2k

@ sepp2k, raise : exn -> 'awięc mogę uzyskać wartość zwracaną, po prostu zignoruję argument.
Gilles „SO- przestań być zły”


Odpowiedzi:


18

Szkielet jest let f x = BODY. W BODY musisz używać x tylko w sposób ogólny (na przykład nie wysyłaj go do funkcji, która oczekuje liczb całkowitych) i musisz zwrócić wartość dowolnego innego typu. Ale jak ta ostatnia część może być prawdziwa? Jedynym sposobem spełnienia instrukcji „dla wszystkich typów 'b, zwracana wartość jest wartość typu 'b”, to upewnienie się, że funkcja nie zwróci. Istnieją dokładnie dwie możliwości: usterka BODY lub nie kończy się. Funkcja raisepowoduje błąd, następujące nie kończą się:

let rec f x = f x

19

Najpierw kilka uwag. Używając tylko podstawowego rachunku lambda nie można uzyskać, 'a -> 'bponieważ system pisania jest zgodny (poprzez izomorfizm Curry'ego Howarda ) z logiką intuicyjną, a odpowiadająca mu formuła A → Bnie jest tautologią.

Inne rozszerzenia, takie jak krotki i dopasowania / warunkowe, nadal zachowują pewną logiczną spójność, dodając typy produktów, *które odpowiadają logicznemu łącznikowi i , i typy sum, |które odpowiadają or . Ponownie, nie oczekuj, że wyprodukują taki 'a -> 'btyp, ponieważ pozwoliłoby to udowodnić jakąś formułę, która nie jest tautologią.

Zatem jedynymi szansami są inne konstrukcje, które wymykają się logice, takie jak raise(ale w tym przypadku nie możesz)… lub let rec! Rekurencja pozwala budować programy, które nigdy się nie kończą, a ich wyniki mogą otrzymać dowolny typ zwrotu, ponieważ nigdy nie zostaną wyprodukowane. Teraz, jeśli pomyślisz o najbardziej trywialnej nie kończącej się funkcji (tej, która bezpośrednio wywołuje się, aby zwrócić wynik):

let rec f x = f x

Zauważysz, że jego typ jest dokładnie taki 'a -> 'b: niezależnie od podanego argumentu, można założyć, że wynik (który nigdy nie zostanie obliczony) może mieć dowolny typ.

Oczywiście fnie jest to interesująca funkcja, ale o to właśnie chodzi. W OCaml każda funkcja, której typ nie wygląda na prawidłową formułę, jest funkcją podejrzaną.


Pytający nie zrozumiał słowa z pierwszych dwóch akapitów, ale podoba mi się twoje zdanie „ich wyniki mogą otrzymać dowolny typ zwrotu, ponieważ nigdy nie zostaną wyprodukowane”.
Gilles „SO- przestań być zły”

1

Używając prymitywów kompilatora możesz napisać to:

external magic: 'a -> 'b = "%identity"

(i rzeczywiście zapewnia to kompilator, choć nie jest to część języka). To jest niebezpieczna obsada tożsamości.

Twój profesor prawie na pewno tego nie chce. Jest to jednak jedyna przydatna funkcja z typem, o 'a -> 'bktórej wiem i faktycznie jest używana w samej dystrybucji OCaml.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.