Во-первых, обратите внимание, что Rank2Types
является устаревшим именем. Это эквивалентно RankNTypes
в современном GH C, и это предпочтительное имя для расширения.
Вот основная проблема. «Список таких обобщенных c функций» может иметь тип:
[forall a. [a] -> [a]]
К сожалению, это недопустимый тип Haskell, потому что Haskell не поддерживает «непредсказуемый полиморфизм». В частности, следующая программа:
{-# LANGUAGE RankNTypes #-}
myFunctions :: [forall a. [a] -> [a]]
myFunctions = [f1, f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
выдает сообщение об ошибке:
DebugRank.hs:2:16: error:
• Illegal polymorphic type: forall a. [a] -> [a]
GHC doesn't yet support impredicative polymorphism
• In the type signature: myFunctions :: [forall a. [a] -> [a]]
Существует расширение, ImpredicativeTypes
. Он ненадежный и неполный, но он позволяет компилировать следующее:
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ImpredicativeTypes #-}
myFunctions :: [forall a. [a] -> [a]]
myFunctions = [f1, f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
debug :: [forall a. [a] -> [a]] -> Bool
debug = any combine
where
combine :: (forall a. [a] -> [a]) -> Bool
combine f = usefonBool f && usefonInt f
usefonBool f = f [True,True] == [False]
usefonInt f = f [1,2] == [2,1]
main = print (debug myFunctions)
Я все равно рекомендую не использовать его.
Обычной альтернативой является использование оболочки newtype
для функции polymorphi c:
newtype ListFunction = ListFunction (forall a. [a] -> [a])
Для этого требуется некоторый шаблон, но без расширений, кроме RankNTypes
:
myFunctions :: [ListFunction]
myFunctions = [ListFunction f1, ListFunction f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
debug :: [ListFunction] -> Bool
debug = any combine
where
combine :: ListFunction -> Bool
combine (ListFunction f) = usefonBool f && usefonInt f
usefonBool f = f [True,True] == [False]
usefonInt f = f [1,2] == [2,1]
Полный код:
{-# LANGUAGE RankNTypes #-}
newtype ListFunction = ListFunction (forall a. [a] -> [a])
myFunctions :: [ListFunction]
myFunctions = [ListFunction f1, ListFunction f2]
where f1 (x:y:rest) = y:x:rest
f2 = reverse
debug :: [ListFunction] -> Bool
debug = any combine
where
combine :: ListFunction -> Bool
combine (ListFunction f) = usefonBool f && usefonInt f
usefonBool f = f [True,True] == [False]
usefonInt f = f [1,2] == [2,1]
main = print $ debug myFunctions