Elixir:如何使自定义类型实现 ==、< 和 >

Elixir: how to make a custom type implement ==, <, and >

背景:我正在努力将这个 F# discriminated union 转换为 Elixir:

type Suit =
| Diamonds
| Clubs
| Hearts
| Spades

我知道有几种不同的方法可以做到这一点,这不是我的问题。

以下必须为真:

Diamonds == Diamonds
Diamonds < Hearts
Spades > Hearts

我很惊讶地发现 Elixir 没有类似于 Haskell 的 Ord 类型类和 GitHub 上的 implementation 的类似协议(非常几颗星!)

是否有一种广为接受或惯用的方法来使自定义类型具有可比性?

执行此操作的惯用方法是在定义自定义类型的模块中简单地提供 equal?/2 and/or compare/2。这可以在核心库和强大的第三方库中经常看到。

例如,Date.compare/2 具有以下规格

compare(Calendar.date(), Calendar.date()) :: :lt | :eq | :gt

v1.10.0 开始,Elixir 为实现 compare/2:

的结构提供方便的 Enum.sort/2 排序
defmodule User do
  defstruct [:name]
  def compare(%User{name: n1}, %User{name: n2}) when n1 < n2,
    do: :lt
  def compare(%User{name: n1}, %User{name: n2}) when n1 > n2,
    do: :gt
  def compare(%User{}, %User{}), do: :eq
end

users = [
  %User{name: "john"},
  %User{name: "joe"},
  %User{name: "jane"}
]

Enum.sort(users, {:asc, User})
#⇒ [%User{name: "jane"},
#   %User{name: "joe"},
#   %User{name: "john"}]