1

im new in functional programming but i have experience in imperative programming specially on java. i would like to ask how does a value iterate in smlnj i know that on java you can use varName += anyNumber or varName = varName + 1. on smlnj i dont know how to do this and my var value is not iterating here is a sample of my code. thanks in advance.

fun number_in_month (dates : (int*int*int) list , month : int) =
    let
      val total = 0;
    in
      let
        fun check(date : (int*int*int) list , m : int) =
            if #2(hd(date)) = m
            then total + 1  (* this is the problem in the code i don't know
                               how to iterate this like "varName += 1" in java *) 
            else check(tl(date),m)     
      in
        check(dates,month)
      end
    end

this program will check if the dates (on a list) entered exist on the month entered and will output how many dates exist on the month.

for example : number_in_month ([(year,month,day)],monthEntered) number_in_month([(2017,2,1),(2015,2,3),(2012,1,2)],2) output must be 2 because the first and second item in the list is equal to the monthEntered.

the problem in my code is it just output 1 even if the all of the dates i input is equal to the month i enter. i just want to know why it just output 1 and how should i fix it. Thanks in advance :D

sshine
  • 15,635
  • 1
  • 41
  • 66
  • You are thinking in terms of mutable values, which means that you are thinking imperatively rather than functionally. You can of course add 1 to a value, but you can't (by using the pure functional parts of SML) cause a value to mutate so as to become 1 more than its current value. – John Coleman Apr 17 '17 at 13:13
  • sorry im new to functional programming, how should i deal with this problem? can you give me an example or link where i can understand it :D Thanks :) – Daniel B. Soriano Apr 17 '17 at 13:37

2 Answers2

2

An equivalent of updating a mutable variable through iteration is re-binding an immutable function parameter through recursion. So instead of "foo() { while (p) { x++; }}", in pseudo-code, you do "foo(p,x) { if (p) { foo(p,x+1); } }". Or in SML,

type date = {year : int, month : int, day : int}
fun countMonth month (dates : date list) =
    let fun countMonth' [] count = count
          | countMonth' (d::ds) count =
            if #month d = month
            then countMonth' ds (count+1)
            else countMonth' ds count
    in countMonth' dates 0 end

But here is how I'd write a function that filters the number of dates in a list that belong to a given month using a higher-order function:

type date = {year : int, month : int, day : int}
fun filterMonth month (dates : date list) =
    List.filter (fn d => #month d = month) dates
fun countMonth month dates =
    List.length (filterMonth month dates)
sshine
  • 15,635
  • 1
  • 41
  • 66
0

Generally in a language that doesn't supply loops (for or while) your next choice should always be recursion. In this particular case recursive calls to this function should be how you "increment" the result.

Just think about the problem backwards, "It needs to return 1 in case there's a match, and 0 otherwise" -- this would mean that calling the function inside itself would potentially return a 1 twice, calling it 3 times would return a 1 three times etc. Now, it's only a matter of adding up all the successful times the recursive function call actually returns 1. And don't worry about infinite recursion, since it will return 0 otherwise and make the recursion tree collapse.

fun number_in_month(dates: (int * int * int) list, month: int) =
    if null dates
    then 0
    else
        if #2 (hd dates) = month
        then 1 + number_in_month(tl dates, month) (* <--this is where the magic happens *)
        else number_in_month(tl dates, month)