Just playing around with a possible typeclass-style usage:
```elixir

defclass Kernel.Eq do
  where do
    @operator == # Assuming there is a way to define an operator or so to call 
the next function, otherwise ignore lines like @operator
    eq?(any, any) :: boolean()
  end

  defproperty equals_self(e) do
    true == eq?(e, e)
  endend


defclass Kernel.Ord do
  extend Kernel.Eq

  where do
    compare(any, any) :: boolean()
  end

  defproperty compare_test(l, r) do
    compare(l, r) == case compare(r, l) do
      :< -> :>
      :> -> :<
      := -> :=
    end
  end

  @operator ==
  @spec eq?(any, any) :: boolean
  def eq?(l, r), do: compare(l, r) == := # Implement Kernel.Eq's call

  @operator <
  @spec lt?(any, any) :: boolean
  def lt?(l, r), do: compare(l, r) == :<

  @operator <=
  @spec le?(any, any) :: boolean
  def le?(l, r), do: compare(l, r) in [:<, :=]

  @operator >
  @spec gt?(any, any) :: boolean
  def gt?(l, r), do: compare(l, r) == :>

  @operator >=
  @spec ge?(any, any) :: boolean
  def ge?(l, r), do: compare(l, r) in [:>, :=]
  # Etc... whatever other things you want to implement on thisend

# Some implementation!  I changed the syntax here to be more generically useful
definstance Kernel.Ord(l, r) when is_int(l) and is_int(r) do
  def compare(l, r) do
    cond do
      l<r -> :<
      l>r -> :>
      l===r -> :=
    endend
definstance Kernel.Ord(l, r) when is_float(l) and is_float(r) do
  def compare(l, r) do
    cond do
      l<r -> :<
      l>r -> :>
      l===r -> :=
    endend
definstance Kernel.Ord(l, r) when is_int(l) and is_float(r) do
  def compare(l, r) do
    cond do
      l<r -> :<
      l>r -> :>
      l==r -> :=
    endend
definstance Kernel.Ord(l, r) when is_float(l) and is_int(r) do
  defdelegate compare(l, r), to: Kernel.Ord(r, l)end# Thought honestly for 
basic types you'd probably just have a single Kernel.Ord instance# that tests 
for any basic type and compares appropriately, like via erlang term ordering# 
for everything except `is_struct`'s.  Maybe like this:
definstance Kernel.Ord(l, r) when not is_struct(l) and not is_struct(r) do
  def compare(l, r) do # Default to erlang term ordering for all non-struct 
types
    cond do
      l<r -> :<
      l>r -> :>
      l==r -> := # What to do about float/int comparisons by default, leave it 
loose like `==`, or tight like `===`?
    endend
# A custom typedefmodule MyDate do
  defstruct year: 0, month: 0, day: 0end# Lets support comparing our date with 
any map/struct that has year/month/day keys!
definstance Kernel.Ord(%MyDate{}, %{year: _, month: _, day: _}) when  do
  def compare(d0, d1) do    # delegate to the list compare because I'm lazy
    Kernel.Ord.compare([d0.year, d0.month, d0.day], [d1.year, d1.month, d1.day])
  endend# And let's support both orders
definstance Kernel.Ord(%{year: _, month: _, day: _}, %MyDate{}) when  do
  def compare(d0, d1), do: Kernel.Ord.compare(d1, d0)end

```
Or something like that...



On Tuesday, November 22, 2016 at 9:38:23 AM UTC-7, OvermindDL1 wrote:
>
> A few notes.  :-)
> At:  
> https://github.com/Qqwy/elixir_experimental_comparable/blob/master/lib/comparable.ex#L27-L37
> Shouldn't this:
> ```elixir
>
> defcomparison(Integer, RomanNumeral) do
> def compare(int, %RomanNumeral{num: num}) when num < int, do: :<
> def compare(int, %RomanNumeral{num: num}) when num > int, do: :>
> def compare(int, %RomanNumeral{}) , do: :=
> end
> ```
> Actually be something like:
> ```elixir
> defcomparison(Integer, RomanNumeral) do
> def compare(int, %RomanNumeral{num: num}), do: Comparable.compare(int, num)
> end
> ```
> Even for primitive types it can be a bad idea not to delegate the compare 
> function (the compiler can optimize it or so, especially with macros). 
>  What if someone stuff something that is not an integer in the RomanNumeral 
> somehow, they would then report as equal even when not.  That brings up the 
> thing, maybe it should be defined as:
> ```elixir
> defcomparison(Integer, %RomanNumeral{num: Integer}) do
> def compare(int, %RomanNumeral{num: num}), do: Comparable.compare(int, num)
> end
> ```
> The defcomparison line itself changed to be explicit as to what is 
> accepted (which can be performed via a match/when internally).  Instead of 
> having automatic naming for things like Integer, you could also do this:
> ```elixir
> defcomparison(int, %RomanNumeral{num: num}) when is_int(int) and 
> is_int(num) do
> def compare(int, %RomanNumeral{num: num}), do: Comparable.compare(int, num)
> end
> ```
> And considering that, maybe instead just entirely shrink it down to:
> ```elixir
> defcomparison(int, %RomanNumeral{num: num}) when is_int(int) and 
> is_int(num) do
> Comparable.compare(int, num)
> end
> ```
> I.E., make the `defcomparison` call itself define the function, of which 
> you could put multiple:
> ```elixir
> defcomparison(int, %RomanNumeral{num: num}) when is_int(int) and 
> is_int(num) do
> Comparable.compare(int, num)
> end defcomparison(float, %RomanNumeral{num: num}) when is_float(float) and 
> is_int(num) do Comparable.compare(float, num) end
> ```
> Although in this simple case you could simplify it down to just:
> ```elixir
> defcomparison(v, %RomanNumeral{num: num}) when is_int(num) do
> Comparable.compare(v, num)
> end
> ```
> This states that %RomanNumerals must always hold an integer, but you can 
> compare anything to the integer that you could normally compare to an 
> integer (whether another integer, float, some custom type, etc...).
>
> But the above latest syntax simplifies it, you could put multiple 
> defcomparisons in a row like normal function heads (the 'use Comparable' 
> declaration in the module can do the combining and optimizing work), you 
> use normal Elixir syntax to deconstruct the types and put on when 
> conditions, *and* you could potentially restrict the syntax to not allow 
> costly calls so you could use compares in `when`'s, perhaps something as 
> simple as like:
> ```elixir
> <table class="highlight tab-size js-file-line-container" data-tab-size="8" 
> style="border-collapse: collapse; box-sizing: border-box; tab-size: 8; 
> font-family: 
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/61396ba4-b2df-4686-b755-c4505a28db54%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to