判别联合表F#的两个值之和
Sum of two values of discriminated union list F#
我有练习提出一个函数,该函数对来自可区分联合列表的相同类型的每个值求和,如下所示:
type volume =
| Litre of float
| Galon of float
| Bucket of float
| Bushel of float
let list = [Litre(20.0);Litre(30.0);Galon(2.0);Bucket(5.0);Litre(5.0);Galon(3.0)];
输出应如下所示:
[Litre(55.0);Galon(5.0);Bucket(5.0)]
我已经提供了部分解决方案:
let rec sumSameTypes (list:volume list) =
match list with
| a::b::t -> if a.GetType() = b.GetType() then // and there is part where I don't know how to sum two of these elements
| [] -> failwith "EMPTY"
由于这看起来更像是一个学习问题,我将尝试提供一些提示而不是完整的答案。
虽然 GetType
可以(在这种情况下)用于检查两个已区分的联合值是否属于同一情况,但这并不是特别实用的风格。您将需要使用模式匹配来检查您得到的是什么情况,这也允许您提取数值:
match a with
| Litre(n) -> // Do something with 'n'
// Add all the other cases here
我认为首先要考虑的是您希望得到什么结果 - 我想最简单的选择是获得代表升、加仑、桶和蒲式耳总数的四个数字。
let rec sumSameTypes (list:volume list) : float * float * float * float =
match list with
| [] ->
// For empty list, we just have 0 of everything
0.0, 0.0, 0.0, 0.0
| x::xs ->
// For non-empty list, process the rest recrsively
// and pattern match on `x` to figure out which of
// the numbers you need to increment
这是非常基本的方法,但我认为这是最好的入门方法。通常,您可能会使用类似地图的东西(从单位到值),但是使用看起来更像的类型也是有意义的:
type Unit = Litre | Galon | Bushel | Bucket
type Volume = { Amount : float; Unit : Unit }
这会使它变得更容易,因为您可以使用 Map<Unit, float>
作为结果。
受经典tail-recursive求和函数的启发:
let sum lst =
let rec loop acc = function
| [] -> acc
| h::t -> loop (acc + h) t
loop 0.0 lst
您可以使用具有 4 个累加器(每种类型一个)的本地 tail-recursive 函数:
let sumByType lst =
let rec loop litre gallon bucket bushel = function
| [] -> // return a new volume list built using the accumulators values
| h::t -> // recursive calls with modified accumulators according to h type
loop 0.0 0.0 0.0 0.0 lst
我有练习提出一个函数,该函数对来自可区分联合列表的相同类型的每个值求和,如下所示:
type volume =
| Litre of float
| Galon of float
| Bucket of float
| Bushel of float
let list = [Litre(20.0);Litre(30.0);Galon(2.0);Bucket(5.0);Litre(5.0);Galon(3.0)];
输出应如下所示:
[Litre(55.0);Galon(5.0);Bucket(5.0)]
我已经提供了部分解决方案:
let rec sumSameTypes (list:volume list) =
match list with
| a::b::t -> if a.GetType() = b.GetType() then // and there is part where I don't know how to sum two of these elements
| [] -> failwith "EMPTY"
由于这看起来更像是一个学习问题,我将尝试提供一些提示而不是完整的答案。
虽然 GetType
可以(在这种情况下)用于检查两个已区分的联合值是否属于同一情况,但这并不是特别实用的风格。您将需要使用模式匹配来检查您得到的是什么情况,这也允许您提取数值:
match a with
| Litre(n) -> // Do something with 'n'
// Add all the other cases here
我认为首先要考虑的是您希望得到什么结果 - 我想最简单的选择是获得代表升、加仑、桶和蒲式耳总数的四个数字。
let rec sumSameTypes (list:volume list) : float * float * float * float =
match list with
| [] ->
// For empty list, we just have 0 of everything
0.0, 0.0, 0.0, 0.0
| x::xs ->
// For non-empty list, process the rest recrsively
// and pattern match on `x` to figure out which of
// the numbers you need to increment
这是非常基本的方法,但我认为这是最好的入门方法。通常,您可能会使用类似地图的东西(从单位到值),但是使用看起来更像的类型也是有意义的:
type Unit = Litre | Galon | Bushel | Bucket
type Volume = { Amount : float; Unit : Unit }
这会使它变得更容易,因为您可以使用 Map<Unit, float>
作为结果。
受经典tail-recursive求和函数的启发:
let sum lst =
let rec loop acc = function
| [] -> acc
| h::t -> loop (acc + h) t
loop 0.0 lst
您可以使用具有 4 个累加器(每种类型一个)的本地 tail-recursive 函数:
let sumByType lst =
let rec loop litre gallon bucket bushel = function
| [] -> // return a new volume list built using the accumulators values
| h::t -> // recursive calls with modified accumulators according to h type
loop 0.0 0.0 0.0 0.0 lst