foxy
foxy

Reputation: 60

Generate a Real list from a Int list in SML

Hello every body im training some SMLs and im creating a code to get deviation of a int list . in the process of it , i need to get a Real list out of some numbers in a int list , which it doesnt let me get them. heres my code :

fun mean [] = 0.0
  | mean (first::rest) = 
      let 
        fun sum [] = 0
          | sum (x::xs) = x + sum xs
          
        fun counter [] = 0
          | counter (y::ys) = 1 + counter ys       
      in 
        Real.fromInt (sum (first::rest)) / Real.fromInt (counter (first::rest))
      end;

fun deviation [] = 0.0
  | deviation (first::rest) = 
      let 
        fun diff (x::xs) = (x - mean (x::xs)) :: diff xs;
      in
        diff (first , first::rest) + deviation rest
      end;

the problem is here :

fun diff (x::xs) = (x - mean (x::xs) ) :: diff xs;

Upvotes: 1

Views: 110

Answers (1)

Chris
Chris

Reputation: 36581

diff is a recursive function, but the base case is never defined. When you try to run diff on an empty list, you will get a pattern match error.

You also define diff to accept a list, but you call it with a tuple.

You define diff as returning a list, given that you are using ::, but then you use addition on the result of that function, which will not work.

Improving mean

You can simplify your sum and counter functions with folds.

fun mean [] = 0.0
  | mean lst = 
      let 
        val sum = foldl op+ 0 lst
        val counter = foldl (fn (_, c) => c + 1) 0 lst      
      in 
        Real.fromInt sum / Real.fromInt counter
      end;

But this requires iterating the entire list twice, when both pieces of information can be ascertained at the same time.

fun sumLen(lst) =
  foldl (fn (x, (sum, len)) => (sum+x, len+1)) (0, 0) lst

mean can now be implemented as:

fun mean(lst) =
  let 
    val (sum, len) = sumLen(lst)
  in
    Real.fromInt sum / Real.fromInt len
  end

Deviation

To get the differences from the mean for a list, you need only use map.

fun diffs(lst) =
  let 
    val m = mean(lst)
  in
    map (fn x => Real.fromInt x - m) lst
  end

Consider evaluating the following.

diffs [1, 2, 3, 4, 5, 6, 7, 8]

The result is:

[~3.5, ~2.5, ~1.5, ~0.5, 0.5, 1.5, 2.5, 3.5]

From there you can use map and Math.pow to square those differences, foldl to sum them, divide by the length of the list, and then Math.sqrt to get the standard deviation.

Upvotes: 2

Related Questions