Fun*_*lad 5 haskell memoization
为了简单起见,我将使用这个人为的示例类(重点是我们从方法中获得了一些昂贵的数据):
class HasNumber a where
getNumber :: a -> Integer
getFactors :: a -> [Integer]
getFactors a = factor . getNumber
Run Code Online (Sandbox Code Playgroud)
当然,我们可以对这个类进行memoizing实现,例如:
data Foo = Foo {
fooName :: String,
fooNumber :: Integer,
fooFactors :: [Integer]
}
foo :: String -> Integer -> Foo
foo a n = Foo a n (factor n)
instance HasNumber Foo where
getNumber = fooNumber
getFactors = fooFactors
Run Code Online (Sandbox Code Playgroud)
但是,要求将"因子"字段手动添加到将成为HasNumber
实例的任何记录中似乎有点难看.下一个想法:
data WithFactorMemo a = WithFactorMemo {
unWfm :: a,
wfmFactors :: [Integer]
}
withFactorMemo :: HasNumber a => a -> WithFactorMemo a
withFactorMemo a = WithFactorMemo a (getFactors a)
instance HasNumber a => HasNumber (WithFactorMemo a) where
getNumber = getNumber . unWfm
getFactors = wfmFactors
Run Code Online (Sandbox Code Playgroud)
这将需要大量的样板原始的所有其他业务提升a
到WithFactorMemo a
,虽然.
有没有优雅的解决方案?
这是解决方案:丢失类型类.我在这里和这里谈过这个.TC a
每个成员将其a
作为参数的任何类型类都与数据类型同构.这意味着您的HasNumber
类的每个实例都可以用这种数据类型表示:
data Number = Number {
getNumber' :: Integer,
getFactors' :: [Integer]
}
Run Code Online (Sandbox Code Playgroud)
即,通过这种转变:
toNumber :: (HasNumber a) => a -> Number
toNumber x = Number (getNumber x) (getFactors x)
Run Code Online (Sandbox Code Playgroud)
而且Number
显然也是一个例子HasNumber
.
instance HasNumber Number where
getNumber = getNumber'
getFactors = getFactors'
Run Code Online (Sandbox Code Playgroud)
这种同构性向我们表明,这个类是伪装的数据类型,它应该死掉.只需使用Number
.最初可能不明白如何做到这一点,但有一点经验应该很快到来.例如,您的Foo
类型变为:
data Foo = Foo {
fooName :: String,
fooNumber :: Number
}
Run Code Online (Sandbox Code Playgroud)
您的备忘录将免费提供,因为这些因素存储在Number
数据结构中.