记忆和类型

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)

这将需要大量的样板原始的所有其他业务提升aWithFactorMemo a,虽然.

有没有优雅的解决方案?

luq*_*qui 7

这是解决方案:丢失类型类.我在这里这里谈过这个.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数据结构中.