如何在 F# 中对受歧视联合的子集进行建模?

How to model a subset of a discriminated union in F#?

我想要一个事物(人,物体,无论什么)有能力(跳跃,运行,等等)。我希望某些东西只具有某些能力。这些是我目前的类型:

type Ability =
  | Jump
  | Stay
  | Run
  | Walk

type Person = {
  abilities : Ability Set // OK, since a person should be able to do all of the above
}

type InanimateObject = {
  abilities : Ability Set // Not OK, it should only be able to "Stay"
}

type ThingWithAbilities =
  | Person of Person
  | InanimateObject of InanimateObject

我希望 API 的来电者能够请求具有特定能力的 ThingWithAbilities。示例:给我 ThingWithAbilities 中具有 "Jump" 能力的所有对象。我怎样才能很好地建模呢?我想让代码中无法创建具有 "jump" 能力的 InanimateObject

如果您想以类型安全的方式执行此操作,则需要为不同的能力集定义不同的类型:

type InanimateAbility =
  | Stay

type AnimateAbility = 
  | Jump
  | Run
  | Walk

type Ability = 
  | Inanimate of InanimateAbility
  | Animate of AnimateAbility

type Person = {
  abilities : Ability Set
}

type InanimateObject = {
  abilities : InanimateAbility Set
}

这里,InanimateAbility是只有无生命物体才有的能力类型,AnimateAbility是有生命物体独有的能力类型。 Ability 结合了这两者,代表了任何一种能力。 Person 可以有一组 Abilitiy 值,但是您可以将 InanimateObject 的能力限制为一组 InanimateAbility 值。

只要您没有太多组合,这就可以正常工作 - 如果您有四种不同类型的对象,它们具有不同的能力子集,那么它可能会变得混乱。在这种情况下,您可能只使用一种类型进行运行时检查,以确保您只为每个对象分配允许的能力。

您可以分别对它们建模,然后参考原子能力

定义您的Person/Object类型
type Jump = Jump
type Stay = Stay
type Run = Run
type Walk = Walk

type Person = {
  abilities : Choice<Jump,Stay,Run,Walk> Set
}

type InanimateObject  = {
  abilities : Stay Set // actually haveing this as a set is a bit odd...but whatever
}

type ThingWithAbilities =
    | Person of Person
    | InanimateObject of InanimateObject