首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >寻找关于使用标记值进行分类更改问题的反馈

寻找关于使用标记值进行分类更改问题的反馈
EN

Stack Overflow用户
提问于 2021-03-08 06:55:38
回答 1查看 45关注 0票数 1

A我在自学F#。我正在解决一个问题,使旧的英国货币单位发生变化。一半的问题是用三元组解决的,然后你要用一个记录再次解决问题。好消息是我已经得到了我的三重解决方案,我相信我也可以让记录变体工作。

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

代码如下

代码语言:javascript
复制
(*
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?
*)
EN

回答 1

Stack Overflow用户

发布于 2021-03-08 07:11:02

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

代码语言:javascript
复制
type OldBritishCurrency = int * int * int

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

代码语言:javascript
复制
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)

在这种表示中,您将失去一些可读性,因为元组只是三个未命名的整数。这就是记录会更好的地方:

代码语言:javascript
复制
type OldBritishCurrency = { Pounds:int; Shillings:int; Pence:int }

如果你修改上面的代码来使用它,你会得到一个更好更易读的解决方案!

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66522344

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档