I am puzzled with my code:
let sum l = match l with
| [] -> 0.0
| h::t -> h +. (sum t);;
It should give me the sum of the numbers in the list. However when I check the code, I found the second code crashes when I use a list of length greater than or equal to 7. Here is the code:
# sum [0.;1.;2.;3.;4.;5.;]
- : float = 15.
# sum [0.;1.;2.;3.;4.;5.;6.]
- : float = 21.
# sum [0.;1.;2.;3.;4.;5.;6.;7.]
- : float = 21.
I am really confused because a modification of it, which operates on int, turned out to be normal:
let rec sumf l = match l with
| []-> 0.0
| h::t-> (float_of_int h) +. sumf t;;
and I do not know what is the essential difference between the two aside from I cast int into float in the second code.
let sum l=
match l with
[]->0.0
|h::t-> h+. (sum t);;
Since you didn't use the rec keyword here, the call to sum in the last line is a call to a sum function that you defined beforehand. Apparently that sum function was buggy.
I don't understand why your code crashes. When I try your sum function with rec keyword, I don't have any problem, otherwise you can't call recursively the sum function.
let rec sum l =
match l with
[] -> 0.
| h :: t -> h +. (sum t);;
You can also use the fold_left function in module List:
let sum l = List.fold_left (+.) 0. l;;
Related
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;
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.
Lets say we have a record which defines students:
type student = {
name : string;
age : int;
grades : (float) list;
}
And safe them in a list like this:
let studentlist = [ {name="alex"; age=7; grades=[1.;2.;3.]} ;
{name="bianca"; age=6; grades=[1.;1.;2.]} ];;
My aim is to compute the grade average of a special student which I choose per age, I select the student with the function search:
let search a lst = List.find( fun {age;_} -> a = age)lst
And compute the average with the help-functions , named sum, length and finally avr :
let rec sum lst =
match lst with
| [] -> 0.0
| h :: t -> h +. sum t
let length lst = float_of_int (List.length lst);;
let avr lst = sum lst /. length lst;;
I don't know how to combine those functions to compute the average properly!
Most of what you've done seems to work. For instance, search works.
utop # search 7 studentlist;;
- : student = {name = "alex"; age = 7; grades = [1.; 2.; 3.]}
If you want to access the grades field of that record, use . for record access.
utop # (search 7 studentlist).grades;;
- : float list = [1.; 2.; 3.]
Now that you have a list of float values, finding the sum or average of them should be easy by passing that value as an argument to the relevant function you've already defined.
Bear in mind that when you use List.find in search, if you search for an age that is not present, you will get a Not_found exception that you will want to handle.
As an aside, note that your avr function iterates over the list twice. Once to compute the sum, and ocne to compute the length.
It is possible to computer the sum, the length, and the average in a single pass. We can use a fold to do this. First off, we can define a basic left fold:
let rec foldl f init lst =
match lst with
| [] -> init
| x::xs -> foldl f (f init x) xs
Consider using this to compute the length of a list:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
When evaluated:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
foldl (fun i _ -> i + 1) (0 + 1) [2.; 3.]
foldl (fun i _ -> i + 1) (1 + 1) [3.]
foldl (fun i _ -> i + 1) (2 + 1) []
3
But we can pass a tuple of values to foldl, building up the length, sum, and average as we go.
utop # let (len, sum, avg) = foldl
(fun (len, sum, avg) x ->
let sum = sum +. x in
let len = len + 1 in
let flen = float_of_int len in
(len, sum, sum /. flen))
(0, 0., 0.)
[1.; 2.; 3.];;
val len : int = 3
val sum : float = 6.
val avg : float = 2.
type Googol = {
number : float
power : float
result : float
}
let generatePowers (n:float) : list<Googol> =
let rec powerInner (n:float) (p:float) (acc : list<Googol>) =
match n with
| p when p <= 1.0 -> acc
| p when p > 1.0 -> powerInner n (p-1.0) ([{ number=n; power=p; result=n**p}]#acc)
let rec numberInner (n:float) (acc : list<Googol>) =
match n with
| n when n <=1.0 -> acc
| n when n >1.0 -> numberInner (n-1.0) ((powerInner n [])#acc)
numberInner n []
ProjectEuler.fsx(311,50): error FS0001: This expression was expected to have type
'Googol list'
but here has type
'Googol list -> Googol list'
I am trying to solve this problem -> https://projecteuler.net/problem=56 | but for this I need to generate powers below n < 100. When I try to concatenate [{ number=n; power=p; result=n**p}]#acc
these lists I get the error above. Explain please why error says 'Googol list -> Googol list' is in the function, does I plug a function as a parameter to the function or I plug the actual list when just after concatenation. Is # a function?
This looks like homework or practice, so first I'll give some hints to move on. Finally I'll show a version that seems to work, and then tell how I would approach the problem.
The task is to find the number a ** b, for a and b less than 100, that has the highest sum of its own digits.
The first problem is that float won't give us all the digits of a ** b, so that type is useless to solve the problem. To fix that, we turn to the BigInteger type, and the BigInteger.Pow function. Then we get a 1 followed by 200 zeroes if we run the following snippet, just like it says in the problem description.
let x: bigint = BigInteger.Pow (100I, 100)
let x: string = string x
printfn "s=%s" x
To get useful results, change the Googol type so that it uses bigint, except for power that should be an int.
Why are the functions powerInner and numberInner inside the function generatePowers? This doesn't seem to have a specific purpose, so I suggest moving them out to make this clearer.
The function powerInner do a match on n, but then goes on to name the results p, which shadows the p parameter so that it is unused. Ok, the intention here is probably to match on p rather than n, so just fix that, and then the shadowing of the p parameter is perfectly fine.
The tests first on <= 1 and then on > 1 causes incomplete matches. If the first line checks that the number is less or equal to one, then it must the greater than one in the next line. So just use n -> without the when to fix that. I also suspect you want to test <= 0 instead of 1.
This
[{ number=n; power=p; result=n**p}]#acc
can be just
{ number=n; power=p; result=n**p } :: acc
and here
(powerInner n [])
I suspect you just need a starting value for the power, which would be 99
(powerInner n 99 [])
SPOILER WARNING
After a bit of tinkering, this is what I ended up with, and it seems to print out a useful list of numbers. Note that in order to not run through all 99 by 99 results with printouts, I've used low starting numbers 3 and 5 for the countdowns here, so we get some simple printout we can study for analysis.
type Googol = { number: bigint; power: int; result: bigint }
let rec powerInner (n: bigint) (p: int) (acc: Googol list) =
match p with
| p when p <= 0 -> acc
| p ->
let newNumber = { number = n; power = p; result = n ** p }
printfn "newNumber=%0A" newNumber
powerInner n (p - 1) (newNumber :: acc)
let rec numberInner (n: bigint) (acc: Googol list) =
match n with
| n when n <= 0I -> acc
| n -> numberInner (n - 1I) ((powerInner n 5 []) # acc)
let generatePowers (n: bigint) : Googol list =
numberInner n []
let powers = generatePowers 3I
I'm not sure if this solution is correct. I'd do it differently anyway.
I would simply loop through a and b in two loops, one inside the other. For each a ** b I would convert the result to a string, and then sum the digits of the string. Then I'd simply use a mutable to hold on to whichever result is the highest. The same could be achieved in a more functional way with one of those fancy List functions.
You're missing a parameter here:
| n when n >1.0 -> numberInner (n-1.0) ((powerInner n [])#acc)
^^^^^^^^^^^^^^^
here
powerInner is defined with three parameters, but you're only passing two.
In F# it is not technically illegal to pass fewer parameters than defined. If you do that, the result will be a function that "expects" the remaining parameters. For example:
let f : int -> int -> string
let x = f 42
// Here, x : int -> string
let y = x 5
// Here, y : string
So in your case omitting the last parameter makes the resulting type Googol list -> Googol list, which then turns out to be incompatible with the type Googol list expected by operator #. Which is what the compiler is telling you in the error message.
Hello i have to make exercise with list. I had one with checking arithmetic with lists code :
let rec q3 lista r =
match lista with
| [] -> false
| [x] -> true
| x1::x2::xs -> if r = x2 - x1 then (q3 xs r) else false
q3 [2;4;6] 2;;
But after this excersize i have problem. I have to calculate sum for numbers in list after last negative number
or for all if i have only positive numbers in my list.
this is code for sum . This is pretty easy but how do make this :( I am quite new in f# programming :P Any reflections ?
I have list for exmaple like this :
let lists = [4;-3;1;9]
// sum =10
//calculate
let rec sum values =
match values with
| [] -> 0
| head::tail -> head + sum(tail)
//test
let x = sum lists
I guess that you're learning F# and so I'm not going to show the full answer (then you wouldn't learn much).
You want to sum all numbers in a list after the last negative number. Another way to look at this is that you want to restart the counting (to start from zero again) every time you find a negative number as you are walking over the list.
This is not easy to do with your version of sum, but you can rewrite the sum function to use the accumulator argument (which keeps the sum of numbers so far):
let rec sumAcc acc values =
match values with
| [] ->
// return the sum of values in the list so far
| head::tail ->
// add the value in the 'head' to the sum so far
// and call 'sumAcc' recursively on the rest of the list
let sum values = sumAcc 0 values
Now, you can solve the problem quite easily - because when head is negative, you can just reset the "sum so far" in the accumulator argument. So, you just need to add another case looking like:
| head::tail when head < 0 ->
// Ignore the sum so far and call 'sumAcc' on the rest of the list
let rec sumList acc lst =
match lst with
| [] -> acc
| hd::tl -> hd + sumList acc tl
|hd::tl when hd < 0 -> sumList acc lst
let sum lst = sumList 0 lst ;;
sum [1;2;-5] ;;
Dont know how to do this //'sumAcc' recursively on the rest of the list
sumList acc lst is rather wrong :D because still get -2 value :D
How can I convert float to float option. Here is the function:
let variance (list_ : float list) : float option =
if List.length list_ < 2 then None
else begin
let average tmp_list = List.fold_left(+.) 0. tmp_list /. float(List.length tmp_list) in
let square value = value *. value in
let rec sum tmp_list =
match tmp_list with
| [] -> 0.0
| head::tail -> square (head -. average tmp_list) +. sum tail
in Some (sum list_ /. float(List.length list_))
end
I need sum list_ /. float(List.length list_) to return float option instead of float and I don't know how to do it. I thought if I return float in a float option function it would automatically return float option but I get the following error:
Error: This expression has type float but an expression was expected
of type float option
I have tried wrapping it around Some and failed. Can't seem to find anything on the internet.
EDIT: Added the full code
Your code runs, it just gives the wrong answer. That's because you sum function is incorrect : you should always use the average of the whole list, whereas you use the average from the current element onwards.
let variance l =
let sum l = List.fold_left (+.) 0. l in
let average l =
match List.length l with
0 -> None
| n -> Some (sum l /. float_of_int n) in
match average l with
None -> None
| Some m -> average (List.map (fun x -> (x -. m)**2.) l)