有那種工作像這樣的「模式」:
data Animal m = Animal {
makeSound :: m()
}
cat = Animal {
makeSound = print "Meow!"
}
dog = Animal {
makeSound = print "Woof!"
}
cow = Animal {
makeSound = print "Moo!"
}
animals = [cat, cat, dog, cow]
main = mapM_ makeSound animals
使用這個模式,你可以做一些更多或更少的瘋狂的事情如:
import Data.Maybe
data I a = I {
f :: a,
sup :: Maybe (I a)
}
mkA = I { f = 10, sup = Nothing }
mkB = let a = mkA in I {
f = 5 + f a,
sup = Just a
}
ls = [mkA, mkB, fromJust $ sup mkB]
main = mapM_ (print . f) ls
這種模式可以也可以用來實現類似「工廠」的功能:
import Data.IORef
data Storage m a = Storage {
putData :: String -> m(),
readData :: m String
}
fileStorage path = Storage {
putData = \s -> writeFile path s,
readData = readFile path
}
inMemStorage ref = Storage {
putData = \s -> writeIORef ref s,
readData = readIORef ref
}
readStorage storage = readData storage
chooseStorage "file" = return $ fileStorage "tmp.txt"
chooseStorage "mem" = do
r <- newIORef ""
return $ inMemStorage r
main = do
storage <- chooseStorage "mem"
putData storage "hi there"
txt <- readData storage
print txt
基本上你定義了一個有趣的數據類型ctions作爲其成員,然後定義返回該數據類型實例的「構造函數」(它們只是常規函數)。
面向對象編程和函數式編程有很大的不同。你不能指望什麼在一個範例中有意義的轉換到另一個範例;雖然可以用繼承將對象編碼到Haskell中,但它並不漂亮。如果你能夠給出一個更具體的例子說明你在現實中想要達到的目標 - 超越「你好世界」 - 我們或許能夠在如何實現這一功能風格方面提供更多的幫助。 –
Haskell缺乏名義上的子類型,這使得不可能直接翻譯。在Haskell中,可以通過編寫「數據B = B A」和「實例B某事物(B a)=某事物+ 5」來模擬類似的系統。當然,還有其他的方式 - 你實際做的取決於你的特定用例,這是從這個玩具例子中不可能看出的。 – user2407038
@Benjamin Hodgson謝謝你的回答,我想實現一個簡單的人生模擬。在這個模擬中必須是具有不同行爲的對象/生物,但他們必須繼承某種父親生物。在使用OOP的命令式語言中,通過超級調用可以輕鬆實現,但我不明白如何在haskell中執行此操作。 – Artem