绑定到记录实例的记忆函数的Haskell生存期

问题描述 投票:2回答:1

首先,我是Haskell的初学者,请保持友善:)

请考虑以下示例:

{-# LANGUAGE RecordWildCards #-}

data Item = Item {itemPrice :: Float, itemQuantity :: Float} deriving (Show, Eq)
data Order = Order {orderItems :: [Item]} deriving (Show, Eq)

itemTotal :: Item -> Float
itemTotal Item{..} = itemPrice * itemQuantity

orderTotal :: Order -> Float
orderTotal = sum . map itemTotal . orderItems

是否有可能记住函数orderTotal,因此它仅对Order记录的“实例”执行一次,这是棘手的部分,一旦垃圾回收此命令,绑定到该实例的缓存条目就被消除了?换句话说,我不想拥有一个永远增长的缓存。

评论后编辑:

确实,在这个简单的示例中,记忆的开销可能没有回报。但是您可以想象一个场景,其中我们有一个复杂的值图(例如订单,订单项,产品,客户...),并且有很多基于这些值的派生属性(例如上面的orderTotal)。如果我们为订单总数创建一个字段,而不是使用函数来对其进行计算,则必须非常小心,以免订单不一致。

如果我们可以声明性地表达这些数据相互依赖关系(使用函数而不是字段),然后将作业委托给编译器以优化这些计算,那会不好吗?我相信,使用Haskell这样的纯净语言是可能的,尽管我缺乏这样做的知识。

[为了说明我想说的话,请看下面的代码(在Python中:]

def memoized(function):
    function_name = function.__name__

    def wrapped(self):
        try:
            result = self._cache[function_name]
        except KeyError:
            result = self._cache[function_name] = function(self)
        return result

    return property(wrapped)


class Item:
    def __init__(self, price, quantity):
        self._price = price
        self._quantity = quantity
        self._cache = {}

    @property
    def price(self):
        return self._price

    @property
    def quantity(self):
        return self._quantity

    @memoized
    def total(self):
        return self.price * self.quantity

Item是不可变的(种类),因此我们知道每个派生属性每个实例只能计算一次。这正是memoized函数的功能。除此之外,缓存位于实例本身(self._cache)内部,因此将对其进行垃圾回收。

我正在寻找的是在Haskell中实现类似的功能。

haskell memoization
1个回答
4
投票

记住对特定类型的值的计算的相对简单的方法是将计算的结果带入数据类型并使用智能构造函数。也就是说,将Order数据类型写为:

data Order = Order
  { orderItems :: [Item]
  , orderTotal :: Float
  } deriving (Show, Eq)

请注意,orderTotal字段将替换您的同名功能。然后,使用智能构造函数构造订单:

order :: [Item] -> Order
order itms = Order itms (sum . map itemTotal $ itms)

由于延迟计算,仅在第一次需要时才计算orderTotal字段,此后将缓存该值。当Order被垃圾回收时,显然orderTotal将同时被垃圾回收。

有人会将其打包到模块中,并且仅导出智能构造函数order而不是通常的构造函数Order,以确保永远不会创建带有不一致orderTotal的订单。我担心这些人。他们如何在日常生活中度过,知道自己随时可能双倍杂交?无论如何,这是真正偏执狂的可用选项。

© www.soinside.com 2019 - 2024. All rights reserved.