ListLike包似乎提供你在找什麼。我從來不明白爲什麼它不是更受歡迎。
ListLike除此之外,Prelude中沒有實現的一個原因是因爲如果不調用某些語言擴展(多參數類型類和fundeps或關聯類型),就無法做得很好。有三類容器來考慮:不關心,在他們所有的元素
- 容器(如[])
- 容器,只爲特定元素實現(如字節串)
- 集裝箱它們是元素上的多態,但需要一個上下文 (例如Data.Vector.Storable,它將使用可存儲的 實例保存任何類型的數據。
這裏是一個非常基本的ListLike風格類,而無需使用任何擴展:
class Listable container where
head :: container a -> a
instance Listable [] where
head (x:xs) = x
instance Listable ByteString where --compiler error, wrong kind
instance Listable SV.Vector where
head v = SV.head --compiler error, can't deduce context (Storable a)
這裏container
有種*->*
。這對於字節串不起作用,因爲它們不允許任意類型;他們有種類*
。它也不適用於Data.Vector.Storable向量,因爲該類不包含上下文(Storable約束)。
你可以通過改變你的類定義要麼解決這個問題
class ListableMPTC container elem | container -> elem where
或
class ListableAT container where
type Elem container :: *
現在container
有種*
;它是一個完全應用的類型構造函數。也就是說,你的實例看起來像
instance ListableMPTC [a] a where
但你不再是Haskell98。
這就是爲什麼即使是一個簡單的Listable類型接口也不重要的原因;當你有不同的集合語義來解釋時(例如隊列),它會變得更難一些。另一個非常大的挑戰是可變數據與不可變數據。到目前爲止,我所見過的每一次嘗試(除了一次)都會通過創建一個可變接口和一個不可變接口來解決這個問題。我所瞭解的將這兩者統一起來的界面之一是大腦彎曲,引發了一系列擴展,並且性能相當差。
附錄:字節串
完全猜想我的一部分,但我認爲我們堅持以字節串作爲進化的產物。也就是說,它們是低性能I/O操作的第一個解決方案,使用Ptr Word8
來連接IO系統調用是有意義的。對指針的操作需要可存儲,並且最有可能的必要擴展(如上所述)使多態性工作不可用。現在很難克服它們的勢頭。具有多態性的類似容器當然是可能的,可存儲的vectorvector包實現了這一點,但它並沒有受到任何的歡迎。
字節串是否是多態的,對元素沒有任何限制?我認爲最接近Haskell的是這個數組類型。這不如低級IO的字節串好,因爲數據需要從指針解壓縮到數組的內部格式。數據也被裝箱,這增加了顯着的空間開銷。如果你想要無箱的存儲空間(更小的空間)和高效的C接口,指針是最好的選擇。一旦你有了一個Ptr,你需要Storable,然後你需要在類型類中包含元素類型,所以你需要擴展。這就是說,我認爲,通過適當的擴展可用,這對於任何單個容器實現(modulo mutable/immutable API)來說基本上是一個解決的問題。現在比較困難的部分是提出一組可用於許多不同類型結構(列表,數組,隊列等)的靈活類,並且足夠靈活以實用。我個人預計這會比較簡單,但我可能是錯的。
你能解釋一下你如何想象這方面的工作?由於'[]'有'* - > *'和'ByteString'只是'*',所以顯然不可能有一個帶'ByteString'和'[]'的類作爲實例。 – 2010-09-02 04:25:47
@Travis Brown:你可以用一個簡單參數化的newtype包裝器來做到這一點。這已經被重新創造了幾次,但在這裏的例子是http://hackage.haskell.org/packages/archive/iteratee/0.2.1/doc/html/Data-Iteratee-WrappedByteString.html – Anthony 2010-09-02 04:43:39
如果有一個庫你想要什麼,那麼爲什麼它需要包含在語言本身? – 2010-09-02 04:46:10