正如你所指定,在OrdByKey
類只能有一個實例 每個類型,當它聽起來像你想能夠聲明實例 在您的記錄類型的每個字段。
要做到這一點,您還必須將字段類型放入類 定義中。這讓你做類似如下:
{-# LANGUAGE MultiParamTypeClasses #-}
data Person = Person { name :: String, age :: Int }
class (Ord r) => OrdByKey o r where
orderKey :: o -> r
instance OrdByKey Person Int where
orderKey p = age p
x <=? y = (orderKey x :: Int) <= (orderKey y :: Int)
但是,你只能有每個字段類型一個實例,因此,如果您 Person
類型看起來像
data Person = Person { name :: String, age :: Int, ssn :: String}
,你將不能夠有要在name
和 ssn
字段上進行比較的版本。您可以通過將每個字段換成 newtype
來解決此問題,因此每個字段都有唯一的類型。所以,你的Person
類型看起來像
data Person = Person { name :: Name, age :: Age, ssn :: SSN}
這將導致大量的newtypes
左右浮動,但。
真正的缺點是需要指定 orderKey
函數的返回類型。我會建議使用函數從 Data.Function
寫出適當的比較函數。我認爲像
compareByKey :: (Ord b) => (a -> b) -> a -> a -> Bool
compareByKey = on (<=)
一個 功能概括你的「可以通過一些關鍵比擬」的想法。在這種情況下,您只需要提供 這個函數來提取該密鑰,該密鑰恰好就是您的Person
類型的訪問器 函數。
我想不出一個實例,其中OrdByKey
類將是有益的,並試圖將<=
有多個版本的同一類型的過載好像它會倒在實踐中正確 混淆。
如果您的目標僅僅是根據記錄中的特定字段進行排序,您總是可以爲'Person'定義'Ord'實例來比較該特定字段。 – sabauma 2013-02-08 16:52:58
@sabauma是的,但我正在尋找一種「可以通過一些關鍵」進行比較的概括。 – 2013-02-08 16:57:54
對於此特定示例,請查看[comparison](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Ord.html#v:comparing)函數:'比較你的年齡我' – 2013-02-09 00:39:45