给定一个受歧视的工会案例,你能得到下一个案例吗?

Given a discriminated union case, can you get the next case?

我正在尝试为机器人模拟编写代码。对于方向,我有一个DU:

type Direction = North | East | South | West

当类型为South时,你给出向右转两次的指令,是否有一个选项让值实际上再次从North开始?

你所拥有的是一个定义了 4 个案例的可区分联合。没有自动理解旋转值的方法,但您可以编写自己的函数来实现此目的:

type Direction = North | East | South | West

module Direction = 
    let turnRight = 
        function  //The function keyword is a shortcut for (fun x -> match x with...)
        | North -> East
        | East -> South
        | South -> West
        | West -> North

//Usage
let direction = North
let direction2 = Direction.turnRight direction

注意:在 F# 中,通常在同名模块中声明作用于特定类型的函数。

有一种方法可以使用反射自动获取下一个案例。通常最好尽可能避免反射,但是它的这种用法非常受限,因为它只在您加载模块时运行一次,所以如果它导致异常应该很容易立即发现:

open FSharp.Reflection

let inline getUnionCases<'a> () =
    FSharpType.GetUnionCases typeof<'a>
    |> Array.map (fun case ->
        FSharpValue.MakeUnion(case,[||]) :?> 'a)

type Direction = North | East | South | West

let directions = getUnionCases<Direction>()

let rightDirections =
    directions
    |> Array.mapi (fun i d -> d, directions.[(i + 1) % directions.Length])
    |> Map

let turnRight d = rightDirections |> Map.find d

North |> turnRight // East
West |> turnRight // North
  • 反射发生在计算模块级别值 directions 时,因此它在模块加载时发生一次(即应用程序启动)。如果将此值放在函数或 class 中,那么您将失去这种安全性。

  • 只有 inline 关键字才能在 Fable(F# 到 JS 编译器)中工作

  • 这仅适用于每个 DU 案例都没有数据的情况。如果您将 North 更改为 North of int,此代码将引发异常。