名單

2012-10-12 23 views
2

說我有一組記錄,如名單

data A = A { a:: String } deriving (Show) 
data B = B { b:: String } deriving (Show) 

那麼一些類型的類

class Foo a where 
    foo :: a -> IO() 

instance Foo A where 
    foo c = ... 

而且我也想這樣做

bar = do 
    push (A {a="x"}) 
    push (B {b="y"}) 

這些東西最後列在一個列表中,以便稍後運行,這樣我就可以

map foo l 

我應該編寫模板haskell來生成一個包裝類型並派生實例,以便列表可以是包裝類型?有沒有更智能的方式去解決這個問題?老實說,我被哈斯克爾型系統固定下來了,並且知道必須有更好的方法來做到這一點。

回答

15

有辦法用存在性量化來做到這一點,但這往往是矯枉過正的。更多的Haskell-y方法是先簡單地應用foo並保留一個[IO()]由此產生的動作列表,然後您可以稍後用sequence來運行它們。

+3

又見[FAQ條目(http://www.haskell.org/haskellwiki/FAQ#I.27m_making_an_RPG._Should_I_define_a_type_for_each_kind_of_monster.2C_and_a_type_class_for_them.3F)這一點,並且[文章它鏈接到( http://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/)。 – shachaf

+2

所以你可以用'stuffToDo = [foo A,foo B]'或甚至'stuffToDo :: IO()'定義'stuffToDo :: [IO()]'stuffToDo = foo A >> foo B' – AndrewC

2

一個使用Existential的例子,但我真的不會使用它,並會建議哈馬爾告訴我的。

{-# LANGUAGE ExistentialQuantification #-} 
data A = A String deriving Show 
data B = B String deriving Show 

class Foo a where 
    foo :: a -> IO() 

instance Foo A where 
    foo c = putStrLn $ "FOOA " ++ show c 

instance Foo B where 
    foo c = putStrLn $ "FOOB " ++ show c 

data Wrap = forall a . Foo a => Wrap a 

instance Foo Wrap where 
    foo (Wrap c) = foo c 

bar :: [Wrap] 
bar = [Wrap $ A "x", Wrap $ B "y"] 

main = mapM_ foo bar