Ответ 1
Мы можем получить тип типа, но для этого нам нужно бросить целый набор расширений языка в GHC, включая (в данном случае) более сомнительные UndecidableInstances
и AllowAmbiguousTypes
.
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
import Data.Proxy
Используя ваше определение для KindRep
data KindRep = Star | KFun KindRep KindRep
мы определяем класс Kindable
вещей, чей вид может быть определен
class Kindable x where
kindOf :: p x -> KindRep
Первый пример для этого прост, все из рода *
равно Kindable
:
instance Kindable (a :: *) where
kindOf _ = Star
Получение типа более высокого сорта затруднено. Мы попытаемся сказать, что если мы сможем найти вид своего аргумента и вид результата применения его к аргументу, мы сможем выяснить его вид. К сожалению, поскольку у него нет аргумента, мы не знаем, какой тип будет его аргументом; поэтому нам нужно AllowAmbiguousTypes
.
instance (Kindable a, Kindable (f a)) => Kindable f where
kindOf _ = KFun (kindOf (Proxy :: Proxy a)) (kindOf (Proxy :: Proxy (f a)))
В сочетании, эти определения позволяют нам писать такие вещи, как
kindOf (Proxy :: Proxy Int) = Star
kindOf (Proxy :: Proxy Maybe) = KFun Star Star
kindOf (Proxy :: Proxy (,)) = KFun Star (KFun Star Star)
kindOf (Proxy :: Proxy StateT) = KFun Star (KFun (KFun Star Star) (KFun Star Star))
Просто не пытайтесь определить тип поликидного типа, например Proxy
kindOf (Proxy :: Proxy Proxy)
который, к счастью, приводит к ошибке компилятора всего за конечный промежуток времени.