defmodule ListOps do @moduledoc """ A set of operations on lists of numbers """ @doc "Returns a list made by squaring each element" @spec square_list(list(number))::list(number) def square_list([]), do: [] def square_list([head | tail]) do [head * head | square_list(tail)] end @doc """ Returns a list made by squaring each element illustrating with """ @spec squares(list(number))::list(number) def squares([]), do: [] def squares(lst) do with num = hd lst do [num*num|squares(tl lst)] end end @doc "returns the sum of the squares of each number in list" @spec sum_squares(list(number))::number def sum_squares(lst), do: Enum.reduce(squares(lst), &+/2) @doc """ Returns a list made by squaring each element illustrating map """ def squares_hof1(lst) when is_list(lst) do Enum.map(lst, fn x -> x * x end) end def squares_hof2(lst) when is_list(lst) do Enum.map(lst, &(&1 * &1)) end @doc """ Returns a list made by applying a function to each element of input list """ @spec map(list(any), function())::list(any) def map([], _f), do: [] def map([head|tail], f), do: [f.(head) | map(tail, f)] @doc """ Applies a function to each successive element in the list, starting with the initial value """ @spec reduce(list(any), any, function())::any def reduce([], init, _f), do: init # _f suppresses compiler warnings def reduce([head|tail], init, f) do reduce(tail, f.(head, init), f) end @spec filter(list(any), function())::any def filter([], _pred), do: [] # _f suppresses compiler warnings def filter([head|tail], pred) do if pred.(head) do [head | filter(tail, pred)] else filter(tail, pred) end end end IO.puts "Square List" IO.inspect ListOps.square_list [1,2,3] # expects [1 4 9] IO.inspect ListOps.square_list [-2,0,5] # expects [4 0 25] IO.inspect ListOps.square_list [] # expects [] #IO.inspect ListOps.square_list ['a', 'b', 'c'] # should be an error IO.puts "squares" IO.inspect ListOps.squares [1,2,3] # expects [1 4 9] IO.inspect ListOps.squares [-2,0,5] # expects [4 0 25] IO.puts "Sum of squares" IO.puts "#{ListOps.sum_squares([1,2,3])}" # expects 14 IO.puts "HOF squares" IO.inspect ListOps.squares_hof1 [1,2,3] # expects [1 4 9] IO.inspect ListOps.squares_hof1 [-2,0,5] # expects [4 0 25] IO.inspect ListOps.squares_hof1 [] # expects [] IO.inspect ListOps.squares_hof2 [1,2,3] # expects [1 4 9] IO.inspect ListOps.squares_hof2 [-2,0,5] # expects [4 0 25] IO.inspect ListOps.squares_hof2 [] # expects [] IO.puts "mapping" IO.inspect ListOps.map([], &(&1 * &1)) # expects [] IO.inspect ListOps.map([1,2,3], &(&1 * &1)) # expects [1,4,9] IO.inspect ListOps.map([-2,0,-5], &(&1 * &1)) # expects [4 0 25] #Enum.map([1, 2, 3], ["one", "two", "three"], &({&1, &2})) #Enum.map([1, 2, 3], [10, 20, 30], &(&1 + &2)) IO.puts "reducing" sum = ListOps.reduce([1,2,3], 0, &+/2) IO.puts "Reduce [1,2,3]: #{sum}" sum = ListOps.reduce(ListOps.squares([1,2,3]), 0, &+/2) IO.puts "Reduce squares([1,2,3]): #{sum}" IO.puts "filtering" IO.inspect Enum.filter([1, 2, 3, 4, 5], fn x -> rem(x,2) == 1 end) IO.inspect ListOps.filter([1, 2, 3, 4, 5], fn x -> rem(x,2) == 1 end)