2011-08-07 10 views
9

To głupie pytanie, które trochę mnie podsłuchuje. Dlaczego nie mogę napisać nowego typu z wieloma parametrami, podczas gdy wersja krotki jest w porządku?nowy typ wieloparametrowy sfałszowany krotką?

newtype A = A (Int, Int) 

ten pierwszy jest o wiele ładniejszy w dopasowywaniu wzorców.

+2

Czy przeczytałeś [to] (http://www.haskell.org/haskellwiki/Newtype)? –

+0

@ n.m., Dziękuję za link, ale czy mógłbyś omówić praktyczne kwestie? Czy ma to związek z dopasowaniem '(A _ _)'? Nie rozumiem, dlaczego równoważność tupetu prowadziłaby do nieintuicyjnego zachowania. – gatoatigrado

Odpowiedz

10

newtype A = A Int tworzy typ izomorficzny na Int. Oznacza to, że zachowuje się dokładnie tak jak Int w.r.t. na przykład bottom, ale pod inną nazwą.

Kontrastuje to z data A = A Int, który tworzy typ uniesiony, który zachowuje się inaczej niż Int. Jest inna wartość dodana, która nie jest w Int: A undefined (która jest różna od undefined::A).

Teraz, newtype A = A (Int, Int) tworzy typ izomorficzny na (Int, Int). Co, nawiasem mówiąc, jest dokładnie tym, co robi data A = A Int Int.

Więc jeśli przyznamy, że newtype A = A Int Int jako odpowiednik newtype A = A (Int, Int), co mamy? newtype A = A Int Int jest odpowiednikiem newtype A = A (Int, Int), co jest równoważne z data A = A Int Int.

newtype A = A Int Int odpowiada data A = A Int Int (tak newtype jest zbędny w tym przypadku), ale

newtype A = A Int jest nie równoważne data A = A Int (który jest cały punkt o newtype w pierwszej kolejności).

Musimy więc stwierdzić, że newtype A = A Int Int jest równoważne z newtype A = A (Int, Int) tworzy nadmiarowość i niespójność, a my lepiej nie pozwalamy na to.

Tam chyba nie ma mowy, aby dać newtype A = A Int Int jakieś inne znaczenie, które jest wolne od tych niespójności (albo byłoby znaleźć i używane przypuszczam;)

7

ponieważ newtype, z grubsza rzecz biorąc, działa jak type przy starcie i jak data podczas kompilacji. Każda definicja data dodaje dodatkową warstwę pośrednią - która w normalnych warunkach oznacza inne wyraźne miejsce, w którym coś może zostać pozostawione jako thunk - wokół wartości, które posiada, podczas gdy newtype nie. "Konstruktor" na newtype jest w zasadzie tylko iluzją.

Wszystko, co łączy wiele wartości w jedną lub daje wybór między wieloma przypadkami, koniecznie wprowadza warstwę pośrednią, aby to wyrazić, więc logiczna interpretacja newtype A = A Int Int byłaby dwiema odłączonymi wartościami Int bez niczego "trzymającego je razem" . Różnica w przypadku newtype A = A (Int, Int) polega na tym, że krotka sama dodaje dodatkową warstwę pośrednią.

Porównaj to z data A = A Int Int vs. data A = A (Int, Int).Pierwsza z nich dodaje jedną warstwę (konstruktor A) wokół dwóch Int s, podczas gdy druga dodaje tę samą warstwę wokół krotki, która sama dodaje warstwę wokół Int s.

Każda warstwa indeksu generalnie dodaje też miejsce, w którym coś może być ⊥, więc rozważ możliwe przypadki dla każdej formy, gdzie? oznacza nie-dolnej wartości:

  • Dla newtype A = A (Int, Int): , (⊥, ?), (?, ⊥), (?, ?)

  • Dla data A = A Int Int: , A ⊥ ?, A ? ⊥, A ? ?

  • Dla data A = A (Int, Int): , A ⊥, A (⊥, ?), A (?, ⊥), A (?, ?)

Jak widać z powyższego, pierwsze dwa są równoważne.


Na Ostatnia uwaga, tu jest zabawa demonstracja, jak newtype różni się od data. Rozważmy następujące definicje:

data D = D D deriving Show 
newtype N = N N deriving Show 

Jakie są możliwe wartości, w tym wszystkie możliwe ⊥, które z nich mają? Jak myślisz, jakie będą dwie poniższe wartości?

d = let (D x) = undefined in show x 
n = let (N x) = undefined in show x 

Załaduj je do GHC i dowiedz się!

Powiązane problemy