F# 具有可选递归组件的可区分联合
F# Discriminated union with optional recurcive component
我正在使用 F#,但在构建我的业务模型时遇到了困难。
假设我有一个浮点数列表和我可以对其应用的两种类型的转换。
例如:
类型转换=
| period:Period 的 SMA
| period:Period
的 P2MA
然后我定义了一个函数 let compute Transformation list
来计算列表上的任何类型的转换。
使用上述转换类型,我可以通过示例创建 SMA(3) 或 P2SMA(5)。
我希望能够以我可以通过示例编写 SMA(3, P2SMA(5, SMA(10))) 的方式嵌套转换。但我也希望仍然能够只编写 SMA(2)。
我尝试使用选项,但我认为编写 SMA(3, None) 或 SMA(3, Some(P2SMA(5))) 太冗长了。
有什么办法吗?也许我的方法是错误的,因为我是 F# 的新手,我可能会以错误的方式解决问题?
非常感谢您的帮助
I tried using options, but I think writing SMA(3, None) or SMA(3, Some(P2SMA(5))) is too verbose.
您可以使用带有可选参数的静态成员:
type Transformation =
| [<EditorBrowsable(EditorBrowsableState.Never)>]
SMAInternal of period:int * inner: Transformation option
...
static member SMA(period:int, ?t:Transformation) =
SMAInternal(period, t)
然后您可以写:Transformation.SMA(3)
或 Transformation.SMA(3, Transformation.P2SMA(5))
。这需要更多的字符,但结构更少。您可能会或可能不会认为它更简洁。
I'm new in F#, I may tackle the problem by the wrong way?
如果您要在一个代码文件中定义数百个这样的东西,那么使用上述方法并缩短名称 Transformation
可能是个好主意。否则只需使用 Somes 和 Nones。冗长是一个可以忽略不计的考虑因素,如果你开始担心它,可怕的事情就会开始发生。
我不太明白你要建模的是什么,但这里有一些类似的东西。
我的转换是数字的倍数或相加
type Trans =
| Mult of period: int
| Add of period: int
我现在可以编写一个解释函数,给定一个数字和一个转换,我可以解释它
let interpret x trans =
match trans with
| Mult p -> p * x
| Add p -> p + x
所以我们现在可以做简单的
让 x = 解释 1 (Mult 2)
但是你想链式转换?
所以让我们允许..
let interprets xs x =
List.fold (fun state trans ->
interpret state trans) x xs
我们可以去...
let foo = [ Mult 3; Add 2 ]
let bar = interprets foo 1
好的,如果你真的想统一处理这些转换列表的组合,这可能很好(有点像函数组合)。
然后我很想去(注意我正在尝试遵循您的编码风格)
(这里有很多东西要吸收,所以也许坚持上面的方法,直到你对 F# 理解得更好一点感到高兴)。
type Trans =
| Mult of period: int
| Add of period: int
| Compose of chain: List<Trans>
let rec interpret x trans =
let interprets xs x =
List.fold (fun state trans ->
interpret state trans) x xs
match trans with
| Mult p -> p * x
| Add p -> p + x
| Compose ps ->
interprets ps x
let two = interpret 1 (Mult 2)
let three = interpret 1 (Compose [ Mult 2; Add 1 ])
现在我认为您有一个“有效”的数据模型,而且非常简单。
然后我不会尝试更改数据模型以使您的代码更方便,我会创建实用程序函数(智能构造函数)来做到这一点。
例如
let multThen x trans = Compose [ Mult x; trans ]
let addThen x trans = Compose [ Add x; trans ]
虽然建议是让数据模型以最简单的方式对数据进行建模,然后使用函数使您的代码优雅,并映射进出该模型,但通常两者看起来完全不同。
警告:我还没有测试过部分代码
不可能完全按照您想要的方式重载受歧视的联合案例。但是如果你接受一个非常不同的语法,你可以这样做:
type Period = int
type SmaTransform =
| Sma of Period
| Sma' of Period * Transform
and P2smaTransform =
| P2sma of Period
| P2sma' of Period * Transform
and Transform =
| OfSma of SmaTransform
| OfP2Sma of P2smaTransform
let SMA(period) =
Sma(period) |> OfSma
let SMA'(period, transform) =
Sma'(period, transform) |> OfSma
let P2SMA(period) =
P2sma(period) |> OfP2Sma
let P2SMA'(period, transform) =
P2sma'(period, transform) |> OfP2Sma
let transforms =
[|
SMA(3)
P2SMA(5)
SMA'(3, P2SMA'(5, SMA(10)))
|]
for transform in transforms do
printfn "%A" transform
与您所需语法的唯一区别是表示嵌套转换的撇号。
我正在使用 F#,但在构建我的业务模型时遇到了困难。 假设我有一个浮点数列表和我可以对其应用的两种类型的转换。 例如:
类型转换= | period:Period 的 SMA | period:Period
的 P2MA然后我定义了一个函数 let compute Transformation list
来计算列表上的任何类型的转换。
使用上述转换类型,我可以通过示例创建 SMA(3) 或 P2SMA(5)。
我希望能够以我可以通过示例编写 SMA(3, P2SMA(5, SMA(10))) 的方式嵌套转换。但我也希望仍然能够只编写 SMA(2)。 我尝试使用选项,但我认为编写 SMA(3, None) 或 SMA(3, Some(P2SMA(5))) 太冗长了。
有什么办法吗?也许我的方法是错误的,因为我是 F# 的新手,我可能会以错误的方式解决问题?
非常感谢您的帮助
I tried using options, but I think writing SMA(3, None) or SMA(3, Some(P2SMA(5))) is too verbose.
您可以使用带有可选参数的静态成员:
type Transformation =
| [<EditorBrowsable(EditorBrowsableState.Never)>]
SMAInternal of period:int * inner: Transformation option
...
static member SMA(period:int, ?t:Transformation) =
SMAInternal(period, t)
然后您可以写:Transformation.SMA(3)
或 Transformation.SMA(3, Transformation.P2SMA(5))
。这需要更多的字符,但结构更少。您可能会或可能不会认为它更简洁。
I'm new in F#, I may tackle the problem by the wrong way?
如果您要在一个代码文件中定义数百个这样的东西,那么使用上述方法并缩短名称 Transformation
可能是个好主意。否则只需使用 Somes 和 Nones。冗长是一个可以忽略不计的考虑因素,如果你开始担心它,可怕的事情就会开始发生。
我不太明白你要建模的是什么,但这里有一些类似的东西。
我的转换是数字的倍数或相加
type Trans =
| Mult of period: int
| Add of period: int
我现在可以编写一个解释函数,给定一个数字和一个转换,我可以解释它
let interpret x trans =
match trans with
| Mult p -> p * x
| Add p -> p + x
所以我们现在可以做简单的 让 x = 解释 1 (Mult 2)
但是你想链式转换? 所以让我们允许..
let interprets xs x =
List.fold (fun state trans ->
interpret state trans) x xs
我们可以去...
let foo = [ Mult 3; Add 2 ]
let bar = interprets foo 1
好的,如果你真的想统一处理这些转换列表的组合,这可能很好(有点像函数组合)。
然后我很想去(注意我正在尝试遵循您的编码风格) (这里有很多东西要吸收,所以也许坚持上面的方法,直到你对 F# 理解得更好一点感到高兴)。
type Trans =
| Mult of period: int
| Add of period: int
| Compose of chain: List<Trans>
let rec interpret x trans =
let interprets xs x =
List.fold (fun state trans ->
interpret state trans) x xs
match trans with
| Mult p -> p * x
| Add p -> p + x
| Compose ps ->
interprets ps x
let two = interpret 1 (Mult 2)
let three = interpret 1 (Compose [ Mult 2; Add 1 ])
现在我认为您有一个“有效”的数据模型,而且非常简单。
然后我不会尝试更改数据模型以使您的代码更方便,我会创建实用程序函数(智能构造函数)来做到这一点。
例如
let multThen x trans = Compose [ Mult x; trans ]
let addThen x trans = Compose [ Add x; trans ]
虽然建议是让数据模型以最简单的方式对数据进行建模,然后使用函数使您的代码优雅,并映射进出该模型,但通常两者看起来完全不同。
警告:我还没有测试过部分代码
不可能完全按照您想要的方式重载受歧视的联合案例。但是如果你接受一个非常不同的语法,你可以这样做:
type Period = int
type SmaTransform =
| Sma of Period
| Sma' of Period * Transform
and P2smaTransform =
| P2sma of Period
| P2sma' of Period * Transform
and Transform =
| OfSma of SmaTransform
| OfP2Sma of P2smaTransform
let SMA(period) =
Sma(period) |> OfSma
let SMA'(period, transform) =
Sma'(period, transform) |> OfSma
let P2SMA(period) =
P2sma(period) |> OfP2Sma
let P2SMA'(period, transform) =
P2sma'(period, transform) |> OfP2Sma
let transforms =
[|
SMA(3)
P2SMA(5)
SMA'(3, P2SMA'(5, SMA(10)))
|]
for transform in transforms do
printfn "%A" transform
与您所需语法的唯一区别是表示嵌套转换的撇号。