Стандартный прием заключается в использовании экзистенциалов.
data Exists f where Exists :: f a -> Exists f
data Dict c a where Dict :: c a => Dict c a
С помощью этих двух инструментов вы можете написать:
parseAs :: String -> Exists (Dict Read) -> Exists Identity
parseAs s (Exists d) = Exists (go s d) where
go :: String -> Dict Read a -> Identity a
go s Dict = Identity (read s)
Затем вы можете построить значения типа Exists (Dict Read)
на муха, чтобы стоять в качестве представления theType
. Конечно, вы захотите использовать более информативное поле, чем Identity
, в качестве возвращаемого типа, и это может означать, что вам нужно более информативное поле, чем Dict Read
, в качестве ввода, описывающего ваш тип, но трудно сказать гораздо больше о том, как сделать это хорошо, без дальнейших подробностей о том, как вы планируете использовать эту вещь.
И позвольте мне добавить в качестве отступления: я настоятельно рекомендую не следовать этому маршруту. За исключением очень необычных обстоятельств, существуют альтернативные решения, которые проще и помогут вам получить 1014 *. С таким небольшим контекстом трудно дать очень хороший совет о том, какая альтернатива будет подходящей для вас; возможно, вопрос sh с более подробным обзором того, где вы хотите go и почему вы думаете, что это способ добраться туда, будет уместным.