small medium large xlarge

20 Oct 2014, 18:11
Pankaj Doharey (1 post)

This is a problem set in the elixir Book to find out the maximum value in a list.

defmodule Maximum do
  def greater(a,b) when a > b , do: a
  def greater(a,b) when a < b , do: b

  def max([]), do: IO.puts "What The hell? How am i supposed to do that ?"
  def max([head]), do: head
  def max([head | tail] ) do
     greater(head , max(tail))

Maximum.max [2,3,4,5,9,1]

Is there a better and more elegant way of doing this ?

05 Nov 2014, 15:39
☺ ☺ (7 posts)

Your greater/2 exists as Kernel.max/2, so you can rewrite your code as:

defmodule Maximum do
  # Renamed to max1 to make distinct from Kernel.max/2
  def max1([]), do: raise "Error: Empty list"
  def max1([head]), do: head
  def max1([head | tail]), do: max(head, max1(tail))

Note that your version won’t work with duplicates in the list (you need a <= case in your greater/2).

Another approach is to use List.foldr/3 or Enum.reduce/2. You don’t need an accumulator, so the latter is probably best:

# Empty list handling propagates from Enum.reduce/2
def max2(list), do: Enum.reduce(list, &Kernel.max(&1, &2))

This is arguably a more functional way to do it. As Dave writes in the book: Recursion is nice, but very very often you will (or should) end up using map/filter/fold or other higher-order functions instead.

There are probably a lot of other interesting ways to do it. Some functional programming humor about the possibilities: The Evolution of a Haskell Programmer