При метапрограммировании может быть полезно (или необходимо) передать системную информацию типа Haskell о типах, известных вашей программе, но не выводимых в Hindley-Milner. Есть ли библиотека (или расширение языка и т.д.), Которая предоставляет возможности для этого - то есть аннотации программных типов - в Haskell?
Рассмотрим ситуацию, когда вы работаете с гетерогенным списком (например, с использованием библиотеки Data.Dynamic
или экзистенциальной квантификации), и вы хотите отфильтровать список до стандартного, однородно типизированного списка Haskell. Вы можете написать такую функцию, как
import Data.Dynamic
import Data.Typeable
dynListToList :: (Typeable a) => [Dynamic] -> [a]
dynListToList = (map fromJust) . (filter isJust) . (map fromDynamic)
и назовите его с помощью аннотации ручного типа. Например,
foo :: [Int]
foo = dynListToList [ toDyn (1 :: Int)
, toDyn (2 :: Int)
, toDyn ("foo" :: String) ]
Здесь foo
- список [1, 2] :: [Int]
; это прекрасно работает, и вы вернулись на твердую почву, где система типа Haskell может сделать свое дело.
Теперь представьте, что вы хотите сделать то же самое, но (а) в то время, когда вы пишете код, вы не знаете, какой должен быть тип списка, созданный вызовом dynListToList
(b), ваша программа содержит информацию, необходимую для ее определения, только (c) она не доступна в форме, доступной для системы типов.
Например, скажите, что вы случайно выбрали элемент из своего гетерогенного списка и хотите отфильтровать список по этому типу. Используя средства проверки типов, предоставляемые Data.Typeable
, ваша программа имеет всю информацию, необходимую для этого, но, насколько я могу судить, в этом суть вопроса: нет способа передать его вместе с типом система. Здесь некоторый псевдо-Haskell, который показывает, что я имею в виду:
import Data.Dynamic
import Data.Typeable
randList :: (Typeable a) => [Dynamic] -> IO [a]
randList dl = do
tr <- randItem $ map dynTypeRep dl
return (dynListToList dl :: [<tr>]) -- This thing should have the type
-- represented by `tr`
(Предположим, что randItem
выбирает случайный элемент из списка.)
Без аннотации типа в аргументе return
компилятор скажет вам, что он имеет "неоднозначный тип" и просит вас его предоставить. Но вы не можете предоставить аннотацию типа вручную, потому что тип не известен во время записи (и может варьироваться); однако тип известен во время выполнения, хотя и в форме, которую система типов не может использовать (здесь требуемый тип представлен значением tr
, a TypeRep
-see Data.Typeable
для деталей).
Псевдокод :: [<tr>]
- это волшебство, которое я хочу совершить. Существует ли какой-либо способ программно указать систему типов с информацией о типе; то есть с информацией о типе, содержащейся в значении в вашей программе?
В основном я ищу функцию с (псевдо) типа ??? -> TypeRep -> a
, которая принимает значение типа, неизвестного системе типа Haskell, и TypeRep
и говорит: "Поверьте мне, компилятор, я знаю, что я" Это дело имеет значение, представленное этим TypeRep
". (Обратите внимание, что это не то, что делает unsafeCoerce
.)
Или есть что-то совершенно другое, что дает мне одно и то же место? Например, я могу представить языковое расширение, которое позволяет присваивать переменные типа, например, расширенную версию расширения, позволяющую использовать переменные типа.
(Если это невозможно или крайне нецелесообразно, например, он требует упаковки полного GHCi-подобного интерпретатора в исполняемый файл - попробуйте объяснить, почему.)