Okazuje się, że zaskakująco trudno poprawnie używać typów egzystencjalnych/rang-n, pomimo bardzo prostego pomysłu.Konieczność wrapperów typu egzystencjalnego
Dlaczego owijanie typów egzystencjalnych w typy data
jest konieczne?
mam następujący prosty przykład:
{-# LANGUAGE RankNTypes, ImpredicativeTypes, ExistentialQuantification #-}
module Main where
c :: Double
c = 3
-- Moving `forall` clause from here to the front of the type tuple does not help,
-- error is the same
lists :: [(Int, forall a. Show a => Int -> a)]
lists = [ (1, \x -> x)
, (2, \x -> show x)
, (3, \x -> c^x)
]
data HRF = forall a. Show a => HRF (Int -> a)
lists' :: [(Int, HRF)]
lists' = [ (1, HRF $ \x -> x)
, (2, HRF $ \x -> show x)
, (3, HRF $ \x -> c^x)
]
Gdybym wykomentuj definicję lists
, kod kompiluje pomyślnie. Jeśli go nie skomentuję, otrzymuję następujące błędy:
test.hs:8:21:
Could not deduce (a ~ Int)
from the context (Show a)
bound by a type expected by the context: Show a => Int -> a
at test.hs:8:11-22
`a' is a rigid type variable bound by
a type expected by the context: Show a => Int -> a at test.hs:8:11
In the expression: x
In the expression: \ x -> x
In the expression: (1, \ x -> x)
test.hs:9:21:
Could not deduce (a ~ [Char])
from the context (Show a)
bound by a type expected by the context: Show a => Int -> a
at test.hs:9:11-27
`a' is a rigid type variable bound by
a type expected by the context: Show a => Int -> a at test.hs:9:11
In the return type of a call of `show'
In the expression: show x
In the expression: \ x -> show x
test.hs:10:21:
Could not deduce (a ~ Double)
from the context (Show a)
bound by a type expected by the context: Show a => Int -> a
at test.hs:10:11-24
`a' is a rigid type variable bound by
a type expected by the context: Show a => Int -> a at test.hs:10:11
In the first argument of `(^)', namely `c'
In the expression: c^x
In the expression: \ x -> c^x
Failed, modules loaded: none.
Dlaczego tak się dzieje? Czy drugi przykład nie powinien być równoważny pierwszemu? Jaka jest różnica między tymi zastosowaniami typów n-rangowych? Czy można w ogóle pominąć dodatkową definicję ADT i używać tylko prostych typów, gdy chcę tego rodzaju polimorfizm?
Dziękuję bardzo za wyjaśnienia. Wszystkie odpowiedzi były ogromnie pomocne, ale myślę, że dostałem "brakujące kawałki układanki" z twojej odpowiedzi, więc zaznaczam to jako zaakceptowane. –