【发布时间】:2015-03-27 20:39:27
【问题描述】:
假设我有这样的类型:
data Stock = Stock {
_stockSymbol :: String,
_stockFairValue :: Float,
_stockBuyAt :: Float,
_stockCurrentPrice :: Float
} |
Etf {
_etfSymbol :: String,
_etfFairValue :: Float,
_etfBuyAt :: Float,
_etfCurrentPrice :: Float
} deriving (Eq)
Stock 和 Etf 都具有相同的字段。现在我想访问其中一个的符号:
item ^. symbol -- don't care if stock or etf
我可以使用 typeclass 来做到这一点,但我想知道 lens 包是否可以自动为我构建这个镜头?我查看了makeFields 函数,但如果我有单独定义的构造函数,它似乎可以工作:
data Stock = Stock { ... }
data Etf = Etf { ... }
有什么方法可以做到这一点,同时保持它们的类型相同?
编辑:这可行:
makeLensesFor [("_stockSymbol", "symbol"),
("_etfSymbol", "symbol"),
("_stockFairValue", "fairValue"),
("_etfFairValue", "fairValue"),
("_stockBuyAt", "buyAt"),
("_etfBuyAt", "buyAt"),
("_stockCurrentPrice", "currentPrice"),
("_etfCurrentPrice", "currentPrice")
] ''Stock
不确定是否有一种内置方式我不必写出这些字段。
【问题讨论】:
-
您能否将数据类型定义为
Stock { isEtf :: Bool, _stockSymbol :: String, ... }?如果所有字段都相同并且不同之处在于构造函数,那么只需将构造函数设为字段即可。我猜测镜头库不支持您尝试执行的操作,因为通常不鼓励使用多构造函数记录。不过,您可以尝试为两个构造函数使用相同的字段名称,这可能会奏效。 -
@bheklilr 我有一个工作示例,请参阅我的编辑。我可以像你说的那样使用一个字段,但是拥有数据构造函数似乎更好。为什么镜头库不鼓励多构造函数记录?
-
haskell 社区通常不鼓励他们,他们可能很危险。例如,如果我打电话给
_etfBuyAt (Stock "" 0 0 0)怎么办?引入部分函数会失去安全性,这可能会导致应用程序崩溃。 -
啊,有道理。谢谢!后续问题:假设我将其分为两种数据类型,
Stock和Etf,但由于有了镜头,我可以在两者上使用相同的功能。我如何编写一个可以接受任何一个的函数?喜欢getSymbol :: EitherStockOrEtf -> String -
@VladTheImpala 你为什么要这样做?你让自己的生活变得艰难
标签: haskell haskell-lens