[erlang-questions] Pattern Matching Question

Justin Piper justin.piper@REDACTED
Fri Nov 23 20:45:58 CET 2007


I'm working through an introductory tutorial on Erlang, and one of the
exercises asked for a function that returns the number of days in a
given month, which I implemented this way:

   days_in(jan, _     ) ->          31 ;
   days_in(feb, common) -> 28          ;
   days_in(feb, leap  ) ->    29       ;
   days_in(mar, _     ) ->          31 ;
   days_in(apr, _     ) ->       30    ;
   days_in(may, _     ) ->          31 ;
   days_in(jun, _     ) ->       30    ;
   days_in(jul, _     ) ->          31 ;
   days_in(aug, _     ) ->          31 ;
   days_in(sep, _     ) ->       30    ;
   days_in(oct, _     ) ->          31 ;
   days_in(nov, _     ) ->       30    ;
   days_in(dec, _     ) ->          31 ;

   days_in(Month, Year)
   -> days_in(Month, leap(Year)) .

   leap(Year) when Year rem 400 == 0 -> leap   ;
   leap(Year) when Year rem 100 == 0 -> common ;
   leap(Year) when Year rem   4 == 0 -> leap   ;
   leap(Year) when integer(Year)     -> common .

You can either explicitly tell days_in/2 if it is a leap year using
'common' and 'leap', or you can give it an integer and it will
determine whether it is a leap year.

This works, but as you can see, since February is the only month that
is actually different during a leap year, it's the only one that cares
what you pass in the second argument. Since passing something other
than 'leap', 'common' or an integer is surely an error, it'd be nice
if this were indicated for all of the months. Does Erlang provide an
elegant way to do this? I know I could just have two clauses for each
month:

   days_in(jan, common) -> 31 ;
   days_in(jan, leap  ) -> 31 ;

But that seems like needless duplication. I also know I could rewrite
days_in/2 to have just one clause for all twelve months and just use
case to select the correct number of days:

   days_in(Month, Year)
   when Year == common; Year == leap
   -> case { Month, Year }
      of { jan, _     } ->          31 ;
         { feb, common} -> 28          ;
         { feb, leap  } ->    29       ;
         { mar, _     } ->          31 ;
         { apr, _     } ->       30    ;
         { may, _     } ->          31 ;
         { jun, _     } ->       30    ;
         { jul, _     } ->          31 ;
         { aug, _     } ->          31 ;
         { sep, _     } ->       30    ;
         { oct, _     } ->          31 ;
         { nov, _     } ->       30    ;
         { dec, _     } ->          31
      end;

But I think that the version that uses a clause per month is a little
easier to read, particularly if you're just scanning the code. I was
hoping Erlang would have an easy way to say that the second argument
has to be either 'leap', 'common' or an integer, and that anything
else is an error.



More information about the erlang-questions mailing list