[英]Does Haskell support anonymous instances of typeclass?
我在F#中有以下代碼(來自一本書)
open System.Collections.Generic
type Table<'T, 'U> =
abstract Item : 'T -> 'U with get
abstract Discard : unit -> unit
let memoizeAndPermitDiscard f =
let lookasideTable = new Dictionary<_, _>(HashIdentity.Structural)
{new Table<'T, 'U> with
member t.Item
with get(n) =
if lookasideTable.ContainsKey(n) then
lookasideTable.[n]
else
let res = f n
lookasideTable.Add(n, res)
res
member t.Discard() =
lookasideTable.Clear()}
let rec fibFast =
memoizeAndPermitDiscard (fun n ->
printfn "computing fibFast %d" n
if n <= 2 then 1 else fibFast.[n - 1] + fibFast.[n - 2])
如我們所見,抽象類型Table在函數memoizeAndPermitDiscard
采用它的實現。 Haskell可以這樣做嗎?
預先致歉:我不是F#專家,所以我可能會誤讀F#代碼。 但是,如果我沒看錯的話,將其翻譯為Haskell相當簡單:
data Table t u = Table { get :: t -> IO u, discard :: IO () }
memoize :: Hashable t => (t -> u) -> IO (Table t u)
memoize f = do
tbl <- newHashTable
return Table
{ get = \t -> do
result <- lookupHashTable t tbl
case result of
Nothing -> let u = f t in writeHashTable t u tbl >> return u
Just u -> return u
, discard = clearHashTable tbl
}
我假設這里提供了newHashTable
, lookupHashTable
, writeHashTable
和clearHashTable
合適的哈希表實現。 我認為,實現這些功能(或建議提供一個提供這些功能的庫)有點與問題無關。
我也不是F#專家,但是我相信您所描述的是在創建對象的那一刻聲明在哪里創建匿名的一次性子類,該類是如何實現超類或接口方法的? 因此,它實際上是一個匿名類 ,而不是匿名實例(或者,它比其他任何面向對象的實例都更匿名,后者通常沒有固有的名稱,只有變量名稱存儲對它們的引用)。
使用Haskell類型的類/實例確實沒有任何意義。 原因是Haskell實例表示的對象與OO實例完全不同。
OO類的實例是對象(甚至接口的實例也是對象)。 所有類的方法將始終在該類的實例上調用。 因此,在創建新對象時,創建現有類或接口的匿名子類是有意義的。 基本上,您說的是該對象如何實現所需的方法,作為聲明以相同方式實現方法的對象的整個命名類的替代方法,您可以在多個地方實例化該對象。
Haskell類的實例是類型 (這就是為什么將其稱為類型類)的原因。 類的所有方法都必須以某種方式涉及類型,但是不能保證它們采用該類型的輸入 。 例如,考慮1類:
class Monoid' a
where mempty' :: a
mappend' :: a -> a -> a
說一個對象是Monoid'
的實例並沒有什么意義。 如果我要創建一個新對象並且想匿名實例化Monoid'
,我將如何定義mempty'
? mempty'
不是我可以在新對象上調用的操作,它是根本不接收任何輸入(甚至不包含隱式“ this”)並產生值2的操作 。
然后是這樣的:
class Functor' f
where fmap :: (a -> b) -> (f a -> f b)
沒有任何東西是 f
的輸入,它是Functor'
的實例; 談論可能的事情甚至都沒有意義,因為類Functor'
的實例是類型構造函數,需要一個類型參數來產生一個類型,而不是實際包含值的類型。 再說一遍,在我創建一個新對象時說“這是沒有意義的”,這就是該對象實現Functor'
)。
在本地聲明一個新的匿名類型 ,並聲明它如何同時實現某些類型類可能是有意義的。 但是Haskell沒有語法,沒有。
幸運的是,您也無需創建匿名類/實例即可擁有符合已知接口的一次性功能。 函數也是一等值,因此您只能使用其字段為函數的類型 。 然后,您可以在任何地方通過為所有功能字段提供定義來創建該類型的新值。 例如:
data MyInterface = MyInterface
{ foo :: Int -> Bool
, bar :: Int -> String
}
example :: MyInterface -> Int -> (Bool, String)
example impl x
= (foo impl x, bar impl x)
main = do
let impl = MyInterface { foo = even, bar = show }
print $ example impl 7
上面的程序打印(False,"7")
。
1我使用的是Monoid'
而不是Monoid
(以及類似的Functor'
),因為我使用的是實類的簡化。 如果您有興趣,可以使用ghci中的:info Monoid
查看真實定義(或查找文檔)。
2或者,類Monoid'
要求僅存在每個實例化它的類型的值,而mempty'
只是對其的引用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.