2016-08-25 44 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’

,我在這裏很感興趣的唯一的事情是aShow類的,所以我可以用getFoo,如:

main = getLine >>= (print . getFoo) 

回答

4

也許你想忽略從富類型參數。

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是否真的需要它 - 很容易陷入[existential antipattern](https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/)。但只有OP知道。 – chi

+0

@chi是這是存在的thingy,但我不認爲這是一個反模式。我知道我在這裏是少數。 –

+0

我們在這裏做過'Foo'這個工會類型嗎?這相當於數據Foo = IFoo Int | BFoo Bool'? – homam

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

如果fiveFoo :: Foo IntfalseFoo :: Foo Bool,你基本上要求getFoo返回不同的類型取決於你在運行時間內提供哪些價值。你不能那樣做。在Haskell中,所有類型的編譯時間必須爲

如果你只想把事情轉換成字符串,爲什麼不把它作爲一個字符串存儲呢?我猜的答案是,這實際上是對你想解決的實際問題的簡化......(?)

+1

嗯,你是對的。我試圖將我的問題歸結爲最簡單的問題。我想創建一系列'節點a'(類別),以便每個節點處理來自用戶的輸入,並繼續處理另一個「節點b a」或最終結果「b」。 – homam

+1

這更接近我真正的問題:http://stackoverflow.com/questions/39147517/functions-of-gadts – homam

5

你可以使用existential types來創建一個數據類型來隱藏和「攜帶」一個類型類像Show左右。

請注意,使用像這樣的存在類型在Haskell中被認爲是anti-pattern,並且您可能要仔細考慮是否真的想要這樣做:更明確地表明您的類型通常更簡單,更好,更不容易錯誤。

不過,話雖如此,如果你真的想這樣做,這裏是你將如何使用存在的類型與您的例子:

{-# 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

'數據Foo a' ---'a'在這裏是多餘的,裏面的「inner」'a' 'forall'是一個不同的變量! –

+0

當然是哦。修正了,謝謝。 :) –

+2

此外,GADT解決方案與存在解決方案几乎完全相同(因爲OP使用了一個,所以我只使用了GADT)不要GADT包含存在類型? –

相關問題