bentaisan
bentaisan

Reputation: 1094

Count and print matching values in SML

I can't use patterns or folding, per the parameters of the assignment, of which this is a toy example of a particular approach to a larger problem.

When I run the code, I get a '0', naturally. So the question is, how do I get the final value of a_count?

fun num_counter(numbers: int list, a_number: int) =
     let val count = 0
             in
                 let fun count_num(numbers: int list, a_count: int) =
         if null numbers
         then 0
         else if (hd numbers) = a_number
         then count_num(tl numbers, count + 1)
         else count_num(tl numbers, count)
     in
     count       
     end
     end

Upvotes: 1

Views: 71

Answers (2)

sshine
sshine

Reputation: 16105

You can write it shorter using a fold:

fun num_counter (numbers, a_number) =
    let fun count (b_number, total) =
            if a_number = b_number
            then total + 1
            else total
    in foldl count 0 numbers
    end

Here foldl takes three arguments: the function count that accumulates the result when visiting each number, b_number in numbers, the initial value for total being 0 and the numbers to fold over, numbers. When foldl has visited the last number, it uses the last accumulation in total as the result.

foldl is itself defined like this:

fun foldl f e []      = e
  | foldl f e (x::xr) = foldl f (f(x, e)) xr

Or you can filter and take the length which costs a bit more:

fun num_counter (numbers, a_number) =
    length (filter (fn b_number => a_number = b_number) numbers)

Upvotes: 0

qouify
qouify

Reputation: 3910

There are several issues with your code:

  1. Your recursive function count_num is never called.
  2. Your recursion terminates by returning 0 instead of the result you've acumulated so far (a_count).
  3. There is some confusion between parameter a_count that, as I understood holds the number of occurences of a_number and count declared at the second line.

Here is some correction to it:

fun num_counter(numbers: int list, a_number: int) = let
    fun count_num(numbers: int list, count: int) =
      if null numbers
      then count  (*  reached the end of the list =>
                      returned the number of occurences computed  *)
      else if (hd numbers) = a_number
      then count_num(tl numbers, count + 1)
      else count_num(tl numbers, count)
in
    count_num (numbers, 0)  (*  first call of count_num,
                                count initiated to 0  *)
end;

Also note that you can use pattern matching to enhance readability of your recursive function:

fun num_counter(numbers: int list, a_number: int) =
  let fun count_num([], count) = count
        | count_num(i :: tl, count) =
          count_num(tl, if i = a_number then count + 1 else count)
  in
      count_num (numbers, 0)
  end;

Upvotes: 2

Related Questions