A few weeks ago I wanted to start learning Erlang. A co-worker pointed out the Ruby Programming Challenge for Newbies that they were completing in Ruby. I decided to try the RPCFN #4, but write it in Erlang. This probably isn’t the most concise or best implementation, but it was a good exercise to encourage me to look at Erlang.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
%% This was inspired from the ruby programming challenge for newbies.
%%   http://rubylearning.com/blog/2009/11/26/rpcfn-rubyfun-4/

-module (polynomials).
%% -compile(export_all).
-export([poly_epr/1]).
-import(string, [concat/2]).
-import(lists, [append/1]).

%% include the test module
-include_lib("eunit/include/eunit.hrl").


%% Create a polynomial expression from an array of numbers
poly_epr(List) when is_list(List), length(List) >= 2 ->
  P = gen_epr([], List),
  case R=join_epr(P) of
    "" ->
      "0";
    _ ->
      R
  end;
poly_epr(_) ->
  {error, "Need at least 2 coefficients"}.


%% generate the polyonmial expression
gen_epr(Poly, []) ->
  case Poly of
    [] ->
      "0";
    _ ->
      Poly
  end;
gen_epr(Poly, [H|T]) ->
  Poly ++ gen_epr([term(H, length(T))], T).


%% join the expressions term together
join_epr([]) ->
  "0";
join_epr([H|T]) ->
  H ++ append([check_neg(X) || X <- T]).


%% add appropreiate sign in front of expression term
check_neg([]) ->
  "";
check_neg(Val="-" ++ _T) ->
  Val;
check_neg(Val) ->
  concat("+",Val).

%% create an expression term
term(1, Expo) ->
  expo(Expo);
term(-1, Expo) ->
  "-" ++ expo(Expo);
term(0, _Expo) ->
  "";
term(Val, 0) ->
  integer_to_list(Val);
term(Val, Expo) when is_number(Val), is_number(Expo)  -> 
  concat(integer_to_list(Val), expo(Expo));
term(_Val, _Expo) ->
  "".


%% create the exponent expression
expo(1) -> 
  "x";
expo(E) ->
  concat("x^", integer_to_list(E)).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% TESTS

%% term tests
term1_test() ->
  "x^2" = term(1,2).

term_negative_value_test() ->
  "-x^2" = term(-1,2).

term0_test() ->
  "" = term(0,5).

term_zero_exponent_test() ->
  "5" = term(5,0).

term_bad_values_test() ->
  "" = term("str","more").

%% poly tests from  the rpcfn
poly_epr1_test() ->
  ?assert("3x^3+4x^2-3" =:= poly_epr([3,4,0,-3])).  

poly_first_negative_test() ->
  ?assert("-3x^4-4x^3+x^2+6" =:= poly_epr([-3,-4,1,0,6])).

poly_simple_test() ->
  ?assert("x^2+2" =:= poly_epr([1,0,2])).

poly_first_minus_one_test() ->
  ?assert("-x^3-2x^2+3x" =:= poly_epr([-1,-2,3,0])).

poly_all_zera_test() ->
  ?assert("0" =:= poly_epr([0,0,0])).

poly_test_error_test() ->
  {error,Msg} = poly_epr([1]),
  ?assert("Need at least 2 coefficients" =:= Msg).

You need to have eunit setup in your code path. Then you can start the Erlang shell and run the tests. Really, they pass!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ erl
Erlang R13B03 (erts-5.7.4) [source] [smp:2:2] [rq:2] [async-threads:0] [kernel-poll:false]

Eshell V5.7.4  (abort with ^G)
1> c(polynomials).
{ok,polynomials}
2> polynomials:test().
  All 11 tests passed.
ok
3>