A我在自学F#。我正在解决一个问题,使旧的英国货币单位发生变化。一半的问题是用三元组解决的,然后你要用一个记录再次解决问题。好消息是我已经得到了我的三重解决方案,我相信我也可以让记录变体工作。
然而,由于我是一个人在工作,而且这本书没有包含解决的例子,我正在寻找反馈。特别是,我解决这个问题的方式与我使用过程式/命令式语言解决它的方式非常相似。此外,提示符要求我使用模式,但我没有看到我的解决方案将从使用模式中受益的任何地方。此外,我还询问了有关代码中的警告和错误的问题。
代码如下
(*
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?
*)发布于 2021-03-08 07:11:02
我认为你对数据的基本表示有点混乱。您将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 }如果你修改上面的代码来使用它,你会得到一个更好更易读的解决方案!
https://stackoverflow.com/questions/66522344
复制相似问题