如何在F#中对一个判别联合类型的子集进行建模?

5

我希望某个事物(人、物品等)具有一些能力(跳跃、奔跑等)。我希望某些事物只具有特定的能力。以下是目前的类型:

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。如何以最佳方式建模此功能?我希望在代码中无法创建具有“跳跃”能力的InanimateObject

2个回答

7

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

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值中。
只要组合不太复杂,这种方法就行得通——如果你有四种不同类型的对象,各自具有不同的能力子集,那么可能会变得混乱。在这种情况下,你可能只需使用一个类型,并进行运行时检查,以确保仅向每个对象分配允许的能力即可。

3

你可以将它们分别建模,然后使用原子能力定义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

有趣的解决方案。这里的 type Jump = Jump 是一个复杂的对象,其中名称 Jump 指的是 DU,也指的是此 DU 的唯一情况。这可以简化为 type Jump = class end - Charles Roddie
1
我认为在Haskell中,这种结构非常正常。 - MrD at KookerellaLtd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接