2016-08-25 7 views
4

данных Foo a определяется как:Функции для полиморфных типов данных

data Foo a where 
    Foo :: (Typeable a, Show a) => a -> Foo a 
    -- perhaps more constructors 

instance Show a => Show (Foo a) where 
    show (Foo a) = show a 

с некоторыми экземплярами:

fiveFoo :: Foo Int 
fiveFoo = Foo 5 

falseFoo :: Foo Bool 
falseFoo = Foo False 

Как я могу определить любую функцию из b -> Foo a, например:

getFoo :: (Show a, Typeable a) => String -> Foo a 
getFoo "five" = fiveFoo 
getFoo "false" = falseFoo 

Здесь getFoo не печатает проверку с помощью Couldn't match type ‘a’ with ‘Bool’.

Единственное, что меня интересует здесь для a быть класса Show так что я могу использовать getFoo как:

main = getLine >>= (print . getFoo) 

ответ

4

Может быть, вы хотите, чтобы опустить параметр типа из Foo.

data Foo where 
    Foo :: (Typeable a, Show a) => a -> Foo 

instance Show Foo where 
    show (Foo a) = show a 

fiveFoo :: Foo 
fiveFoo = Foo (5 :: Int) -- (Foo 5) doesn't work because of ambiguity 

falseFoo :: Foo 
falseFoo = Foo False 

getFoo :: String -> Foo 
getFoo "five" = fiveFoo 
getFoo "false" = falseFoo 

print $ getFoo "five" -- prints '5' 
print $ getFoo "false" -- prints 'False' 
+5

Мне это нравится, но Интересно, действительно ли OP действительно нуждается в этом - легко попасть в [экзистенциальный антипаттерн] (https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/). Однако только ОП знает. – chi

+0

@chi да это экзистенциальная штука, но я не думаю, что это так много антипаттера. Я знаю, что я здесь меньшинство. –

+0

Мы создали здесь тип объединения «Foo»? Является ли это эквивалентом 'data Foo = IFoo Int | BFoo Bool'? – homam

2
getFoo :: (Show a, Typeable a) => String -> Foo a 
getFoo "five" = fiveFoo 
getFoo "false" = falseFoo 

fiveFoo :: Foo Int Если и falseFoo :: Foo Bool, вы, по сути просят getFoo вернуть другой тип в зависимости от того, какое значение вы кормите его во время выполнения. Вы не можете этого сделать. В Haskell все типы должны быть известны в компиляцией.

Если все, что вы хотите сделать, это преобразовать вещь в строку, почему бы просто не сохранить ее как строку в первую очередь? Я предполагаю, что ответ заключается в том, что на самом деле это упрощение реальной проблемы, которую вы пытаетесь решить ... (?)

+1

Ну, ты прав. Я попытался свести свою проблему к ее простейшей. Я хочу создать серию «Nodes a b» (например, Category), чтобы каждый Node обрабатывал вход пользователя и продолжал либо другой «Node b a», либо с окончательным результатом «b». – homam

+1

Это ближе к моей реальной проблеме: http://stackoverflow.com/questions/39147517/functions-of-gadts – homam

5

Вы можете использовать existential types, чтобы сделать тип данных скрытым и «нести» тип класса подобный Show вокруг.

Обратите внимание, что использование таких экзистенциальных типов, как это, считается anti-pattern в Haskell, и вы, вероятно, захотите тщательно изучить, действительно ли вы хотите это сделать: более подробно о ваших типах обычно проще, лучше и менее подвержено к ошибкам.

Однако, как говорится, если вы действительно хотите сделать это, вот как вы будете использовать экзистенциальные типы с вашим примером:

{-# LANGUAGE ExistentialQuantification #-} 

-- This Foo can only be constructed with instances of Show as its argument. 
data Foo = forall a. Show a => Foo a 

-- Note that there is no "Show a => ..." context here: 
-- Foo itself already carries that constraint around with it. 
instance Show Foo where 
    show (Foo a) = show a 


getFoo :: String -> Foo 
getFoo "five" = Foo 5 
getFoo "false" = Foo False 

main = print . getFoo =<< getLine 

Демонстрация:

ghci> main 
five 
5 
ghci> main 
false 
False 
+3

'data Foo a' ---' a' избыточно здесь, «внутренний» 'a' внутри 'forall' - это другая переменная! –

+0

D'oh, конечно. Исправлено, спасибо. :) –

+2

также, решение GADT почти точно такое же, как экзистенциальное решение (и я использовал GADT только потому, что OP использовал один). Не GADTs включают экзистенциальные типы? –

 Смежные вопросы

  • Нет связанных вопросов^_^