我有一堆保存时间序列数据的类型。比如,一个带有日期的日记帐列表,一个带有交易列表的银行对账单。我想创建一个class
来注解这些类型slice-able
,就像Python切片[:]
一样
这会给所有类型实现TsList
带来一场噩梦,因为:有很多filter
... txns
是共同的。有没有办法把这个共同的逻辑分解出来呢?
data BoundDate = Include Date
| Exclude Date
class TsList a where
subByRange :: a -> Maybe BoundDate -> Maybe BoundDate -> a
--- with Statement type
instance TsList Statement where
subByRange s@(Statement txns) Nothing Nothing = s
subByRange s@(Statement txns) Nothing (Just ed) =
case ed of
Include d -> Statement $ filter ( x -> x <= d ) txns
Exclude d -> Statement $ filter ( x -> x < d ) txns
subByRange s@(Statement txns) (Just sd) Nothing =
case sd of
Include d -> Statement $ filter ( x -> x => d ) txns
Exclude d -> Statement $ filter ( x -> x > d ) txns
subByRange s@(Statement txns) (Just sd) (Just ed) =
Statement $ subByRange _s Nothing (Just ed)
where
_s = Statement $ subByRange s (Just sd) Nothing
--- now with Journal type
instance TsList Journal where
subByRange s@(Journal txns) Nothing Nothing = s
subByRange s@(Journal txns) Nothing (Just ed) =
case ed of
Include d -> Journal $ filter ( x -> x <= d ) txns
Exclude d -> Journal $ filter ( x -> x < d ) txns
subByRange s@(Statement txns) (Just sd) Nothing =
case sd of
Include d -> Journal $ filter ( x -> x => d ) txns
Exclude d -> Journal $ filter ( x -> x > d ) txns
subByRange s@(Statement txns) (Just sd) (Just ed) =
Journal $ subByRange _s Nothing (Just ed)
where
_s = Journal $ subByRange s (Just sd) Nothing
3条答案
按热度按时间3b6akqbq1#
一种选择是在普通的旧列表上实现这些函数,然后类示例就是新类型的 Package 器/非 Package 器。
例如,您可以定义:
然后您的示例就是:
一个潜在的麻烦是,如果你在
TsList
中有一堆类方法(或者一堆示例),而你甚至不想用新类型 Package /展开的相同方式定义每一个方法。你可以利用DefaultSignatures
和Coercible
类型类来编写:因为
Statement
和Journal
只是[Date]
周围的新类型 Package 器,它们将能够使用subByRange
的默认版本,所以您所需要做的就是声明它们是示例。rdrgkggo2#
正如@FyodorSoikin在评论中提到的,最简单的方法可能是使用GHC语言扩展
DerivingVia
。要做到这一点,请在文件顶部添加以下声明:现在,假设您的类型被定义为
newtype
s,如果您告诉GHC这样做,它将能够自动从另一个示例派生一个示例:(Note这仅在
Statement
和Journal
都是相同类型的newtype
Package 器时有效。)polhcujo3#
如果您希望它能够处理更复杂的数据类型,而不是简单的
[Date]
Package 器,那么您将需要一些更高级的工具。幸运的是,GHC提供了一些工具。您可以使用Data.Data
module来更广泛地处理这些工具。首先,我们需要一些工具。许多库导出了与此函数等价的东西,但它足够简单,我将只包含它,而不是引入一个额外的依赖。
(It在边缘情况下,可以大大提高该函数的性能。如果你关心这一点,你应该使用来自库的版本。)
有了这项功能,您就可以利用
DefaultSignatures
扩充功能,在类别中提供适用于任何Data
执行严修的预设实作。从
Statement
的定义中可以看出,它适用于更复杂的数据类型。如果一个类型中有多个[Date]
值,它可能无法完成您想要的操作--在这种情况下,您可以手动写出示例。而且,您可能可以利用filterSubRange
在该过程中是一个独立函数这一事实。