有沒有推薦的方法來使用類型類來模擬類OCaml的參數化模塊?Haskell中的OCaml仿函數(參數化模塊)
對於一個實例,我需要實現複雜的泛型計算的模塊,該模塊可能會使用不同的 misc進行parmetrized。類型,函數等。更具體地說,讓它成爲可以用不同的 類型的值,矢量類型(列表,未裝箱的矢量,矢量,元組等), 和距離計算策略參數化的kMeans實現。爲了方便起見,爲了避免瘋狂量的中間類型,我想要 有這種計算多態的DataSet類,它包含所有的 所需的接口。我還試圖用TypeFamilies避免的類型類參數很多 (也可能會帶來問題):
{-# Language MultiParamTypeClasses
, TypeFamilies
, FlexibleContexts
, FlexibleInstances
, EmptyDataDecls
, FunctionalDependencies
#-}
module Main where
import qualified Data.List as L
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as U
import Distances
-- contains instances for Euclid distance
-- import Distances.Euclid as E
-- contains instances for Kulback-Leibler "distance"
-- import Distances.Kullback as K
class (Num (Elem c)
, Ord (TLabel c)
, WithDistance (TVect c) (Elem c)
, WithDistance (TBoxType c) (Elem c)
)
=> DataSet c where
type Elem c :: *
type TLabel c :: *
type TVect c :: * -> *
data TDistType c :: *
data TObservation c :: *
data TBoxType c :: * -> *
observations :: c -> [TObservation c]
measurements :: TObservation c -> [Elem c]
label :: TObservation c -> TLabel c
distance :: TBoxType c (Elem c) -> TBoxType c (Elem c) -> Elem c
distance = distance_
instance DataSet() where
type Elem() = Float
type TLabel() = Int
data TObservation() = TObservationUnit [Float]
data TDistType()
type TVect() = V.Vector
data TBoxType() v = VectorBox (V.Vector v)
observations() = replicate 10 (TObservationUnit [0,0,0,0])
measurements (TObservationUnit xs) = xs
label (TObservationUnit _) = 111
kMeans :: (Floating (Elem c)
, DataSet c
) => c
-> [TObservation c]
kMeans s = undefined -- here the implementation
where
labels = map label (observations s)
www = L.map (V.fromList.measurements) (observations s)
zzz = L.zipWith distance_ www www
wtf1 = L.foldl wtf2 0 (observations s)
wtf2 acc xs = acc + L.sum (measurements xs)
qq = V.fromList [1,2,3 :: Float]
l = distance (VectorBox qq) (VectorBox qq)
instance Floating a => WithDistance (TBoxType()) a where
distance_ xs ys = undefined
instance Floating a => WithDistance V.Vector a where
distance_ xs ys = sqrt $ V.sum (V.zipWith (\x y -> (x+y)**2) xs ys)
此代碼編譯莫名其妙和工作,但它是很醜陋和哈克。
kMeans應該通過值類型(數字,浮點數,任何東西)進行參數化,框類型(向量,列表,未裝箱的向量,元組可以)和距離計算策略。
也有類型的觀察(這是用戶提供的樣品類型, 應該有很多,包含在每個觀察測量)。
所以問題是:
1)如果函數不包含在它的標誌性的參數類型, 類型將無法被推斷
2)仍然沒有想法,如何類型類WithDistance申報對於不同的距離類型(Euclid,Kullback,其他任何通過幻像類型)有不同的實例 。
目前WithDistance只是多種按框型和值類型,所以如果我們需要 不同的策略,我們可能只會把它們放在不同的模塊中,並導入所需的 模塊。但這是一種黑客和非類型的方法,對嗎?
所有這些在OCaml中都可以用非模塊來完成。在Haskell中實現這些東西的正確方法 是什麼?
帶TypeFamilies的Typeclasses看起來與參數模塊類似,但它們的工作原理與 不同。我真的需要那樣的東西。
我不知道它是否真的被推薦,但GHC 7.8和更高版本允許使用'NullaryTypeClasses'擴展名的空類型類。我想,這將是等待發生的孤兒實例麻煩。 – 2014-10-12 06:37:08
你打算如何使用'TBoxType'?您沒有任何函數會在'WithDistance'或'DataSet'中返回'TBoxType'。 – Cirdec 2014-10-12 07:44:39
一般來說,在Haskell中,這類問題是通過普通的舊數據類型和多態而不是類型類來實現的。這可以讓你免費通過傳遞給函數輕鬆選擇您想要的距離函數。如果需要類型類並且類型可以有多個解釋,那麼通常使用'newtype'來選擇'instance'。例如,「Monoid」類有兩個明顯的整數實現,所以引入'newtype'來區分'Sum'和'Product'。 http://hackage.haskell.org/package/base-4.7.0.1/docs/Data-Monoid.html#t:Sum – Cirdec 2014-10-12 07:48:34