我的意思是定義一個適用於函數中的本地(let
或where
)作用域的類型實例。更重要的是,我希望在這個實例中的函數是閉包,即能夠關閉定義實例的詞法範圍中的變量(這意味着實例可能在下次調用它的函數時以不同方式工作) )。是否有可能有一個「本地」類型實例?
我可以給你一個簡單的用例。假設我有一個基於類型類的類型的函數。在這個例子中,我使用了平方,它可以對任何類型的實例進行操作,例如Num
(是的,平方很簡單,可以很容易地重新實現,但它可能會更復雜)。我需要能夠按原樣使用現有功能(無需更改或重新實現)。
square :: Num a => a -> a
square x = x * x
現在,假設我希望在模運算中使用這個操作,即加法,乘法等mod某些數字。這對於任何固定的模基很容易實現,但我想要有一些通用的東西,我可以重新使用不同的基模。我希望能夠來定義是這樣的:
newtype ModN = ModN Integer deriving (Eq, Show)
-- computes (x * x) mod n
squareModN ::
squareModN x n =
let instance Num ModN where
ModN x * ModN y = ModN ((x * y) `mod` n) -- modular multiplication
_ + _ = undefined -- the rest are unimplemented for simplicity
negate _ = undefined
abs _ = undefined
signum _ = undefined
fromInteger _ = undefined
in let ModN y = square (ModN x)
in y
這樣做的一點是,我需要使用的功能,從上面(square
),要求它的參數是一個類型,它是有一定的實例類型的類。我定義了一個新類型並將其作爲Num
的一個實例;然而,爲了正確地執行模運算,它取決於基模n
,由於該函數的通用設計,其可能因呼叫而改變。我希望將實例函數定義爲square
函數的一次性「回調」(如果您願意的話),以定製它此次(以及僅此一次)執行操作的方式。
一種解決方案可能是將「閉包變量」直接集成到數據類型本身中(即ModN (x, n)
來表示它所屬的數量和基數),操作可以從參數中提取這些信息。然而,這有幾個問題:1)對於多參數函數(例如(*)
),它需要在運行時檢查這些信息是否匹配,這很醜陋; 2)實例可能包含0參數的「值」,我可能想依賴於閉包變量,但是,由於它們不包含參數,因此無法從參數中提取它們。
不,你不能有本地實例。對於模塊化算法,Oleg Kiselyov和CC Shan已經在他們的論文「隱式配置」中解決了這個問題 - http://www.cs.rutgers.edu/~ccshan/prepose/prepose.pdf。我個人傾向於避免這種情況,並簡單地爲模塊化的基礎 - 即Z7,Z12做一個新的類型。 Conal Elliott提供了另一種選擇替代類型的模式,請參閱CxMonoid的文章「適用性數據驅動計算」 - http://conal.net/papers/data-driven/paper.pdf – 2012-03-03 12:42:52
事實上,反射包本質上是Oleg紙的包裝版本。 – ehird 2012-03-03 12:56:49
關於Haskell的現狀:沒有。實例將隨處隨地都可以到達。關於未來對Haskell的可能調整:也許。關於使用你自己的機制,而不是typeclasses:是的。 – 2012-03-03 22:01:02