【问题标题】:What's an alternative to throwing an exception when managing pattern matching with guards?在使用守卫管理模式匹配时,除了抛出异常之外,还有什么替代方法?
【发布时间】:2016-04-09 12:50:12
【问题描述】:

在使用守卫管理模式匹配时,除了抛出异常之外,还有什么替代方法?

[<Literal>]
let Objective = 33

let (|NotGame|IsGame|) p =
    match p with
    | LessThanGame v when v <  Objective -> NotGame v
    | Game         v when v >= Objective -> IsGame  v

警告:

此表达式的模式匹配不完整

我不希望编译器有任何抱怨。

结果,我不想做的是:

let (|NotGame|IsGame|) p =
    match p with
    | LessThanGame v when v <  Objective -> NotGame v
    | Game         v when v >= Objective -> IsGame  v
    | _ -> failwith "idk..."

我宁愿这样做:

let (|NotGame|IsGame|) p =
    match p with
    | LessThanGame v when v <  Objective -> NotGame v
    | Game         v when v >= Objective -> IsGame  v
    | _ v                                -> IsGame  v

完整的代码在这里:

// ***********
// Game of 33 
// ************************************************************
(*Types*)
// ************************************************************
type Player = 
    | Player1
    | Player2

type Shot = 
     | TwoPointer
     | ThreePointer
     | FoulShot
     | TwoFoulShots
     | ThreeFoulShots

type PlayerScore = {Player:Player; Points:Points}

and Points = 
    | LessThanGame of int
    | Game of int

type Posession = Posession of Player

[<Literal>]
let Objective = 33

// ************************************************************
(*Active Patterns*)
// ************************************************************
let (|NotGame|IsGame|) = function
    | LessThanGame v when v <  Objective -> NotGame v
    | Game         v when v >= Objective -> IsGame  v
    | _ -> failwith "idk..."

// ************************************************************
(*Functions*)
// ************************************************************
let makeShot shot (shooter, defender) =

    let ballHandler = shooter.Player
    let points = shooter.Points

    let shotValue = match shot with
                    | TwoPointer   | TwoFoulShots   -> 2
                    | ThreePointer | ThreeFoulShots -> 3
                    | FoulShot                      -> 1

    match points with 
    | NotGame p ->  if p + shotValue < Objective then
                         { Player=ballHandler; Points=LessThanGame (p + shotValue) }, defender
                    else { Player=ballHandler; Points=Game         (p + shotValue) }, defender

    | IsGame  p -> { Player=ballHandler; Points=Game p }, defender

let startGame = 

    let player1Score = { Player=Player1; Points=LessThanGame 0 }
    let player2Score = { Player=Player2; Points=LessThanGame 0 }

    (player1Score, player2Score)

// ************************************************************
(*Client*)
// ************************************************************
let player1Score, player2Score = startGame

let player1, player2 = (player1Score, player2Score) |> makeShot TwoPointer
let shooter, defender = player2, player1

let final = (shooter, defender) |> makeShot ThreePointer
                                |> makeShot FoulShot

                                |> makeShot ThreePointer
                                |> makeShot TwoFoulShots

                                |> makeShot ThreePointer
                                |> makeShot ThreeFoulShots

                                |> makeShot ThreePointer
                                |> makeShot ThreePointer
                                |> makeShot ThreePointer
                                |> makeShot ThreePointer
                                |> makeShot ThreePointer

分辨率:

正如 Guy Coder 所建议的,我使用 if/else 条件作为替代。因此,这消除了我抛出异常的需要。

// ************************************************************
(*Types*)
// ************************************************************
type Player = | Player1 | Player2

type Shot = 
     | TwoPointer| ThreePointer
     | FoulShot  | TwoFoulShots | ThreeFoulShots

type PlayerScore = {Player:Player; Game:Game}

and Game = 
    | Underway of int
    | AlmostGame of int
    | GameTime of int

[<Literal>]
let Objective = 33

[<Literal>]
let MaxFoulShots = 3

let (|Underway|AlmostGame|Game|) (score,shot) =

    let shotValue = match shot with
                    | FoulShot                      -> 1
                    | TwoPointer   | TwoFoulShots   -> 2
                    | ThreePointer | ThreeFoulShots -> 3

    match score, shotValue with
    | Underway   s,v -> if (s + v) <= (Objective - MaxFoulShots)
                        then Underway   (s + v)
                        else AlmostGame (s + v)

    | AlmostGame s,v -> if ( (s+v) < Objective )
                        then AlmostGame (s + v)
                        else Game Objective

    | GameTime   s,v -> Game s

// ************************************************************
(*Functions*)
// ************************************************************
let makeShot shot (shooter, defender) =

    match (shooter.Game, shot) with
    | Underway p   -> { shooter with Game=Underway p }, defender
    | AlmostGame p -> { shooter with Game=AlmostGame p }, defender
    | Game p       -> { shooter with Game=GameTime p }, defender

let startGame = 

    let player1Score = { Player=Player1; Game=Underway 0 }
    let player2Score = { Player=Player2; Game=Underway 0 }

    (player1Score, player2Score)

// ************************************************************
(*Client*)
// ************************************************************
let player1Score, player2Score = startGame

let player1, player2 = (player1Score, player2Score) |> makeShot TwoPointer
let shooter, defender = player2, player1

let final = (shooter, defender) |> makeShot ThreePointer
                                |> makeShot FoulShot

                                |> makeShot ThreePointer
                                |> makeShot TwoFoulShots

                                |> makeShot ThreePointer
                                |> makeShot ThreeFoulShots

                                |> makeShot ThreePointer
                                |> makeShot ThreePointer
                                |> makeShot ThreePointer
                                |> makeShot ThreePointer
                                |> makeShot ThreePointer

                                |> makeShot FoulShot
                                |> makeShot FoulShot
                                |> makeShot ThreeFoulShots

【问题讨论】:

  • 一旦你有一个什么时候编译器停止检查并发出警告,除非你有一个通配符。无法真正修复,我认为昨天有一个骗局
  • 约翰,不同之处在于我有一个附加到联合案例的值。昨天的问题没有附加数据。相反,该值只是一个 int 而不是 union case。
  • 哦,_v 的事情也做不到。仍然是重复的
  • scott wlaschin 建议在您拥有正在执行的代码时不要抛出异常。因此,此代码不执行 I/O。有什么建议吗?
  • 如果我正确理解您的问题,您正试图将输入分类为两个存储桶,条件为less than。如果是这样,那么放弃模式匹配,只使用if 语句。没有规则说必须对所有决策使用模式匹配才能发挥作用。我看到的另一种方式是您尝试在分类的同时进行输入验证。让输入验证处理问题,分类不会有这些异常情况。

标签: f#


【解决方案1】:

如果我正确理解您的问题,您正试图将输入分类为两个存储桶,条件为less than

如果是这样,那么放弃模式匹配,只使用if 语句。没有规则说必须对所有决策使用模式匹配才能发挥作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 2015-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多