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

Set*_*eth 3 functional-programming elixir

背景:我正在将这个 F# 可区分联合转换为 Elixir:

type Suit =
| Diamonds
| Clubs
| Hearts
| Spades
Run Code Online (Sandbox Code Playgroud)

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

以下必须为真:

Diamonds == Diamonds
Diamonds < Hearts
Spades > Hearts
Run Code Online (Sandbox Code Playgroud)

我很惊讶地发现 Elixir 没有类似于 Haskell 的Ord类型类的类似协议和GitHub 上的这个实现(很少有星星!)

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

Set*_*eth 5

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

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

compare(Calendar.date(), Calendar.date()) :: :lt | :eq | :gt
Run Code Online (Sandbox Code Playgroud)

从 开始v1.10.0ElixirEnum.sort/2实现 的结构提供了方便的排序compare/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"}]
Run Code Online (Sandbox Code Playgroud)