You can also define your own type that redefines zero
and operations (this idea is from @andreasnoack originally I think), e.g. something like:
struct SemiRing{T,A,M,Z,O} <: Number
val::T
end
Base.:+(x::SemiRing{T, A, M, Z, O}, y::SemiRing{T, A, M, Z, O}) where {T, A, M, Z, O} = SemiRing{T, A, M, Z, O}(A(x.val, y.val))
Base.:*(x::SemiRing{T, A, M, Z, O}, y::SemiRing{T, A, M, Z, O}) where {T, A, M, Z, O} = SemiRing{T, A, M, Z, O}(M(x.val, y.val))
Base.zero(::Type{SemiRing{T, A, M, Z, O}}) where {T, A, M, Z, O} = SemiRing{T, A, M, Z, O}(Z)
Base.zero(::SemiRing{T, A, M, Z, O}) where {T, A, M, Z, O} = SemiRing{T, A, M, Z, O}(Z)
Base.one(::Type{SemiRing{T, A, M, Z, O}}) where {T, A, M, Z, O} = SemiRing{T, A, M, Z, O}(O)
Base.one(::SemiRing{T, A, M, Z, O}) where {T, A, M, Z, O} = SemiRing{T, A, M, Z, O}(O)
then you use it as
S = SemiRing{Float64,max,+,-Inf,0.0}
using SparseArrays
x=sparse(1:10, 1:10, ones(S,10))