F# 使用标记值查找有关分类更改问题的反馈

F# 使用标记值查找有关分类更改问题的反馈,f#,pattern-matching,F#,Pattern Matching,A我自己在学法语。我正在研究一个问题,以改变旧的英国货币单位。一半的问题要用一个三元组来解决,然后你要用一个记录来再次解决这个问题。好消息是我已经得到了我的三重解决方案,我相信我可以让记录变量也工作 然而,由于我是一个人工作,而且书中没有解决的例子,我正在寻找反馈。特别是,我解决这个问题的方式与我使用过程/命令式语言解决它的方式非常相似。此外,提示要求我使用模式,但我看不到我的解决方案从使用模式中受益的地方。此外,我还问了一些关于代码中的警告和错误的问题 代码如下 (* 3.2 The form

A我自己在学法语。我正在研究一个问题,以改变旧的英国货币单位。一半的问题要用一个三元组来解决,然后你要用一个记录来再次解决这个问题。好消息是我已经得到了我的三重解决方案,我相信我可以让记录变量也工作

然而,由于我是一个人工作,而且书中没有解决的例子,我正在寻找反馈。特别是,我解决这个问题的方式与我使用过程/命令式语言解决它的方式非常相似。此外,提示要求我使用模式,但我看不到我的解决方案从使用模式中受益的地方。此外,我还问了一些关于代码中的警告和错误的问题

代码如下

(*
3.2 The former British currency had 12 pence to a shilling and 20 shillings to a pound. 
Declare functions to add and subtract two amounts, represented by triples (pounds, shillings, pence) of integers, 
and declare the functions when a representation by records is used. 
Declare the functions in infix notation with proper precedences, 
and use patterns to obtain readable declarations.

Hansen, Michael R.; Rischel, Hans. Functional Programming Using F# (p. 66). Cambridge University Press. Kindle Edition. 
*)

(*
 My strategy is to convert pounds, shillings, and pence to the smallest unit, pence, then rebuild a normalized form of 
 change from just pence.

 Addition and subtraction are done in Pence converted to int.
*)

type OldBritishCurrency = | Pound of int
                          | Shilling of int
                          | Pence of int

let pencePerShilling = 12
let shillingPerPound = 20
let pencePerPound = shillingPerPound * pencePerShilling

// OldBritishCurrency.Pence != int and I don't know how to overload an (int (Pence x)) cast yet
let penceToInt (Pence p) = p

(*
Ch03.fsx(87,39): warning FS0025: Incomplete pattern matches on this expression. 
    For example, the value 'Pence (_)' may indicate a case not covered by the pattern(s).

I am thinking of OldBritishCurrency as a type with subtypes Pound, Shilling, and Pence,
However, a tagged type is obviously NOT a subtype, at least not exactly.

The warning message and the question seem to assume the need for a pattern to ID the tag.

This function converts Pound * Shilling * Pence to Pence.
*)
let oldBritishChangeToPence(Pound bp, Shilling s, Pence p) =
    Pence (bp * pencePerPound + s * pencePerShilling + p)

let penceToShillingsAndPence(Pound bp, Shilling s, Pence p) =
    (Pound bp, Shilling (s + p / pencePerShilling), Pence (p % pencePerShilling))

let shillingsToPoundsAndShillings(Pound bp, Shilling s, Pence p) =
    (Pound (bp + s / shillingPerPound), Shilling (s % shillingPerPound), Pence p)

//Converts Pence to Pound * Shilling * Pence in standard form
let penceToNormalizedOldBritishCurrency (Pence p) = 
        penceToShillingsAndPence(Pound 0, Shilling 0, Pence p)  |> shillingsToPoundsAndShillings
        
let (.+.) (Pound bp, Shilling s, Pence p) (Pound bp', Shilling s', Pence p') =
    let a = penceToInt(oldBritishChangeToPence(Pound bp, Shilling s, Pence p)) // don't know how to overload +
    let b = penceToInt(oldBritishChangeToPence(Pound bp', Shilling s', Pence p'))
    penceToNormalizedOldBritishCurrency(Pence (a + b))

let (.-.) (Pound bp, Shilling s, Pence p) (Pound bp', Shilling s', Pence p') =
    let a = penceToInt(oldBritishChangeToPence(Pound bp, Shilling s, Pence p)) // don't know how to overload -
    let b = penceToInt(oldBritishChangeToPence(Pound bp', Shilling s', Pence p'))
    penceToNormalizedOldBritishCurrency(Pence (a - b))

// testing

oldBritishChangeToPence(Pound 2, Shilling 2, Pence 3)

penceToNormalizedOldBritishCurrency(Pence 507)

oldBritishChangeToPence(Pound 10, Shilling 10, Pence 0)

penceToNormalizedOldBritishCurrency(Pence 2520)

penceToNormalizedOldBritishCurrency(Pence 253)

//

oldBritishChangeToPence(Pound 0, Shilling 19, Pence 11)

penceToNormalizedOldBritishCurrency(Pence(507 + 239))

(Pound 2, Shilling 2, Pence 3) .+. (Pound 0, Shilling 19, Pence 11)

penceToNormalizedOldBritishCurrency(Pence(507 - 239))

(Pound 2, Shilling 2, Pence 3) .-. (Pound 0, Shilling 19, Pence 11)

penceToNormalizedOldBritishCurrency(Pence(239 - 507))

(Pound 0, Shilling 19, Pence 11) .-. (Pound 2, Shilling 2, Pence 3)

//

oldBritishChangeToPence(Shilling 0, Shilling 1, Pence 1)
(*
Microsoft.FSharp.Core.MatchFailureException: The match cases were incomplete
at FSI_0053.oldBritishChangeToPence(OldBritishCurrency _arg1, OldBritishCurrency _arg2, OldBritishCurrency _arg3) 
in C:\Users\trent\Source\Repos\HansenAndRischelCh03\HansenAndRischelCh03\Ch03.fsx:line 0
at <StartupCode$FSI_0054>.$FSI_0054.main@()
Stopped due to error

So, if I don't use a pattern, I get a warning, but when I provide Shilling and Pound is expected, I get an error
similar to a type match error ... which is GOOD!  It's just what I want.

Can I ignore the previous warning?

And if I can protect myself with something akin to type checking, what is the pattern matching 
    the question wanted me to include?
*)
(*
3.2前英国货币为12便士兑一先令,20先令兑一英镑。
声明用于加和减两个金额的函数,以整数的三倍(磅、先令、便士)表示,
并在使用记录表示时声明函数。
以中缀符号声明函数,并具有适当的优先级,
并使用模式获取可读的声明。
《使用F#的函数式编程》(第66页),剑桥大学出版社,Kindle版。
*)
(*
我的策略是将英镑、先令和便士转换成最小的单位便士,然后重建标准化的货币形式
从一便士变为一便士。
加法和减法是用便士换算成整数的。
*)
键入OldBritishCurrency=|整数磅
|国际先令
|整数便士
让铅笔刷=12
每磅先令=20
让铅笔包=先令每磅*铅笔包
//旧英国货币。便士!=我还不知道如何使(int(Pence x))的施法过载
设penceToInt(Pence p)=p
(*
fsx(87,39):警告FS0025:此表达式上的模式匹配不完整。
例如,值‘Pence(_)’可能表示图案未涵盖的情况。
我认为旧英国货币是一种亚类型英镑、先令和便士的货币,
但是,标记类型显然不是子类型,至少不完全是。
警告消息和问题似乎假定需要一个模式来标识标记。
此函数用于将英镑*先令*便士转换为便士。
*)
让旧不列颠换币(英镑bp,先令s,便士p)=
便士(英国石油公司*pencePerPound+s*pencePerShilling+p)
让铅笔先令和便士(英镑bp,先令s,便士p)=
(英镑bp,先令(s+p/铅笔销售),便士(p%铅笔销售))
让先令停止点和先令(英镑bp,先令s,便士p)=
(英镑(bp+s/先令每磅)、先令(s%先令每磅)、便士p)
//以标准形式将便士转换为英镑*先令*便士
让penceToNormalizedOldBritishCurrency(便士p)=
铅笔先令和便士(0英镑,0先令,便士p)|>先令秒针和先令
let(+)(英镑bp,先令s,便士p)(英镑bp,先令s,便士p')=
让a=penceToInt(旧英国的changetepence(磅bp,先令s,便士p))//不知道如何过载+
设b=铅笔点数(旧不列颠货币兑换率(英镑bp',先令s',便士p'))
便士标准化英国货币(便士(a+b))
let(.-)(英镑bp,先令s,便士p)(英镑bp,先令s,便士p’)=
让a=penceToInt(旧英国的changetepence(磅bp,先令s,便士p))//不知道如何过载-
设b=铅笔点数(旧不列颠货币兑换率(英镑bp',先令s',便士p'))
便士标准化英国货币(便士(a-b))
//测试
旧不列颠货币(2英镑,2先令,3便士)
英国货币(507便士)
旧不列颠货币(10英镑,10先令,0便士)
英国货币(2520便士)
英国货币(253便士)
//
旧不列颠货币(0英镑,19先令,11便士)
便士标准化英国货币(便士(507+239))
(2英镑,2先令,3便士)。+。(0英镑,19先令,11便士)
英国货币(507-239便士)
(2英镑,2先令,3便士)。(0英镑,19先令,11便士)
英国货币(239-507便士)
(0英镑,19先令,11便士)。(2英镑,2先令,3便士)
//
旧不列颠货币(0先令,1先令,1便士)
(*
Microsoft.FSharp.Core.MatchFailureException:匹配案例不完整
在FSI_0053.oldBritishChangeToPence(OldBritishCurrency_arg1、OldBritishCurrency_arg2、OldBritishCurrency_arg3)
在C:\Users\trent\Source\Repos\hansenadrischelch03\hansenadrischelch03\Ch03.fsx中:第0行
地址:$FSI_0054.main@()
由于错误而停止
所以,如果我不使用模式,我会得到一个警告,但当我提供预期的先令和英镑时,我会得到一个错误
类似于类型匹配错误…这很好!这正是我想要的。
我可以忽略前面的警告吗?
如果我可以用类似于类型检查的方法来保护自己,那么模式匹配是什么呢
我想问的问题是什么?
*)

我认为您对数据的基本表示有点混乱。您将
OldBritishCurrency
定义为一个有区别的联盟,可以是英镑、先令或便士。但是,您不能使用它来表示可以在这三种更改中指定的数据。您通常需要英镑、先令和便士,最好使用元组:

type OldBritishCurrency = int * int * int
然而,我认为你把英镑、先令和便士转换成便士的想法很有效。使用元组表示法可以很容易地做到这一点:

let pencePerShilling = 12
let shillingPerPound = 20
let pencePerPound = shillingPerPound * pencePerShilling

let oldBritishToPence (bp, s, p) =
    (bp * pencePerPound + s * pencePerShilling + p)

let penceToOldBritish p =
    let s = p / pencePerShilling
    (s / shillingPerPound, s % shillingPerPound, p % pencePerShilling)
在这种表示法中,您正在失去一些可读性,因为元组只是三个未命名的整数。这是记录更好的地方:

type OldBritishCurrency = { Pounds:int; Shillings:int; Pence:int }
如果您修改上面的代码来使用它,您将得到一个更好、更可读的解决方案

我想