- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在编写一个程序,将财务报表转码为 a ledger .在那个程序中,我有代表不同事件的类型:
data Withdrawal = Withdrawal { wTarget :: !Text, wAmount :: !Cash, wBalance :: !Cash }
data Fee = { fFee :: !Cash, fBalance :: !Cash }
-- many more
我使用这些类型,因为我有特定于交易类型的函数。
我还想编写一个将 CSV 记录转换为这些类型的事件解析器,因此我创建了一个 Activity
求和类型:
data Activity =
ActivityFee Fee
| ActivityWithdrawal Withdrawal
| -- ...
parseActivity :: CsvRecord -> Activity
那个 Activity
非常样板化。必须为新的事件类型创建一个新的 Activity*
构造函数有点麻烦。
这个问题是否有更惯用或更好的设计模式?如果是 C++,std::variant
会很方便,因为添加新的事件类型不需要添加新的样板构造函数。
我考虑过类型类,但它们的问题是它们不是封闭的,我无法通过模式匹配来创建像 applyActivity::Activity -> Wallet -> Wallet
这样的函数>。我看到我可以将 applyActivity
变成 Activity
类的函数,但问题是只有一个参数使用此模式时,此解决方案才简单明了。如果我们有两个参数,如 foo::(ClassOne a, ClassTwo b) => a -> b -> c
,那么 foo
应该属于哪个类就不清楚了.
最佳答案
一个选项是不用定义总和类型,而是生成 parseActivity
返回 Wallet -> Wallet
表征事件的操作,包裹在一些Parser
输入 Alternative
实例。
parseActivity :: CsvRecord -> Parser (Wallet -> Wallet)
你仍然需要定义一个大的 Parser
使用一堆 <|>
的值组成了Parser
s 用于每个可能的事件。
Wallet -> Wallet
以外的其他操作可以通过使解析器返回函数记录来支持:
data ActivityOps = ActivityOps {
applyActivity :: Wallet -> Wallet,
debugActivity :: String
}
这仍然不如 sum 类型通用,因为它预先限制了我们可能对事件执行的操作。为了支持新操作,我们需要更改 Parser ActivityOps
值(value)。使用 sum 类型,我们只需定义一个新函数。
此解决方案的一个变体是定义一个类型类,例如
class ActivityOps a where
applyActivity :: a -> Wallet -> Wallet
debugActivity :: a -> String
并制作Parser
返回某种存在主义,例如:
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTSyntax #-}
data Activity where
MakeActivity :: ActivityOps a => a -> Activity
这有时是 frowned upon , 但它的好处是能够轻松调用 ActivityOps
已知类型事件的方法。
关于haskell - 我怎样才能在 Haskell 中简洁地表示异类求和类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71192855/
我是一名优秀的程序员,十分优秀!