序數

我們將通過實現自定義型別序數來了解如何實現自定義比較。為簡化實現,我們將重點關注這些數字的一小部分:所有序數最多但不包括ε0。我們的實施重點是簡單,而不是速度; 但是,實施也不慢。

我們按照康托爾的正常形式儲存序數。因為序數算術不是可交換的,所以我們將採用儲存最重要術語的通用約定。

immutable OrdinalNumber <: Number
    βs::Vector{OrdinalNumber}
    cs::Vector{Int}
end

由於 Cantor 正規形式是唯一的,我們可以簡單地通過遞迴相等來測試相等性:

Version >= 0.5.0

在 v0.5 版本中,有一個非常好的語法可以緊湊地執行此操作:

import Base: ==
α::OrdinalNumber == β::OrdinalNumber = α.βs == β.βs && α.cs == β.cs

Version < 0.5.0

否則,將函式定義為更典型的:

import Base: ==
==(α::OrdinalNumber, β::OrdinalNumber) = α.βs == β.βs && α.cs == β.cs

要完成我們的訂單,因為這種型別有一個總訂單,我們應該過載 isless 函式:

import Base: isless
function isless(α::OrdinalNumber, β::OrdinalNumber)
    for i in 1:min(length(α.cs), length(β.cs))
        if α.βs[i] < β.βs[i]
            return true
        elseif α.βs[i] == β.βs[i] && α.cs[i] < β.cs[i]
            return true
        end
    end
    return length(α.cs) < length(β.cs)
end

為了測試我們的訂單,我們可以建立一些方法來生成序數。當然,零是通過 Cantor 正常形式的條款獲得的:

const ORDINAL_ZERO = OrdinalNumber([], [])
Base.zero(::Type{OrdinalNumber}) = ORDINAL_ZERO

我們可以定義一個 expω來計算ω^α,並用它來計算 1 和ω:

expω(α) = OrdinalNumber([α], [1])
const ORDINAL_ONE = expω(ORDINAL_ZERO)
Base.one(::Type{OrdinalNumber}) = ORDINAL_ONE
const ω = expω(ORDINAL_ONE)

我們現在有一個關於序數的全功能排序函式:

julia> ORDINAL_ZERO < ORDINAL_ONE < ω < expω(ω)
true

julia> ORDINAL_ONE > ORDINAL_ZERO
true

julia> sort([ORDINAL_ONE, ω, expω(ω), ORDINAL_ZERO])

4-element Array{OrdinalNumber,1}:
                                                                                                       OrdinalNumber(OrdinalNumber[],Int64[])
                                                                     OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[],Int64[])],[1])
                                   OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[],Int64[])],[1])],[1])
 OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[OrdinalNumber(OrdinalNumber[],Int64[])],[1])],[1])],[1])

在最後一個例子中,我們看到序數的列印可能會更好,但結果是預期的。