I created my own datatype And I'm trying to create the sum of all the numbers in that datatype which is a list of lists. I don't want to use any F# libraries
My datatype
type elist = A | L of int * elist
I'm a beginner in F# and trying to grasp my head on it. I want to do this recursively. My thinking going into it is to traverse to the end of the list and start an sum and go back to the front and add each one.
example:
let l = L(4, L(3, L(6, L(3, A))))
that should return
val it : int 16
Here's my code and I know it is wrong:
let rec sum l =
let a = 0
match l with
| A -> 0
| L(head,A) -> head
| L(head,tail) -> sum tail + a
You're nearly there. All you need is to lose the a:
let rec sum l =
match l with
| A -> 0
| L(head,A) -> head
| L(head,tail) -> head + sum tail
Then evaluating sum l when l = L(4, L(3, L(6, L(3, A)))) gives
val it : int = 16
as required.
Related
Directly using recursion, write a function truesAndLength : bool list -> int * int that
returns both the length of the list (in the first component of the pair), and the number of
elements of the list that are true (in the second component). Your function must only iterate
over the elements of the list once. (Do not use any of the functions from the List module.)
this is my code so far:
let rec length bs =
match bs with
| [] -> 0
| b::bs -> 1 + length bs
let rec trues bs =
match bs with
| [] -> 0
| b::bs -> if b = true then 1 + trues bs else trues bs
let truesandlength bs =
let l = length bs
let t = trues bs
(l, t)
truesandlength [true; true; false]
This works by im iterating through the list 2 times, i can't figure out how to iterate only 1. Any tips?
Based on your comments, here's how I suggest you think about the b::bs case:
Call truesAndLengths recursively on the tail of the list. This gives you tTail (the # of trues) and lTail (the length) of the tail.
Compute t and l for the full list based on the value of b. (E.g. l is one more than lTail.)
Return t, l.
The key is to call truesAndLengths recursively in only one place in your code, passing it the tail of the list.
let rec truesAndLength bs =
let sum a b = (fst a + fst b, snd a + snd b)
match bs with
| [] -> 0, 0
| head::tail ->
if head then sum (1,1) (truesAndLength tail) else sum (1, 0) (truesAndLength tail)
Directly using recursion, write a function truesAndLength : bool list -> int * int that
returns both the length of the list (in the first component of the pair), and the number of
elements of the list that are true (in the second component). Your function must only iterate
over the elements of the list once. (Do not use any of the functions from the List module.)
this is my code so far:
let rec length bs =
match bs with
| [] -> 0
| b::bs -> 1 + length bs
let rec trues bs =
match bs with
| [] -> 0
| b::bs -> if b = true then 1 + trues bs else trues bs
let truesandlength bs =
let l = length bs
let t = trues bs
(l, t)
truesandlength [true; true; false]
This works by im iterating through the list 2 times, i can't figure out how to iterate only 1. Any tips?
Based on your comments, here's how I suggest you think about the b::bs case:
Call truesAndLengths recursively on the tail of the list. This gives you tTail (the # of trues) and lTail (the length) of the tail.
Compute t and l for the full list based on the value of b. (E.g. l is one more than lTail.)
Return t, l.
The key is to call truesAndLengths recursively in only one place in your code, passing it the tail of the list.
let rec truesAndLength bs =
let sum a b = (fst a + fst b, snd a + snd b)
match bs with
| [] -> 0, 0
| head::tail ->
if head then sum (1,1) (truesAndLength tail) else sum (1, 0) (truesAndLength tail)
While doing practice, I build a simple function that returns the biggest value in a list:
let rec findMax = // Find maximum value in list
fun l ->
let rec aux =
fun l k ->
match l with
| [] -> k
| x::xs -> if x >= k then aux xs x
else aux xs k
aux l 0
Meanwhile, I built a similar function to find the smallest element in a list:
let finMin = //Find smallest value in list
fun l ->
let rec aux =
fun l k ->
match l with
| [] -> k
| x::xs -> if x <= k then aux xs x
else aux xs k
aux l 0
Here the problem: I initialized both aux functions with k = 0. It is only partially fine: findMax works properly as long as no negative values are in the list. Similarly, findMin works well only with negative numbers.
What should be the proper value to efficiently initialize k? Is there a system-dependant value? Should i previously calculate it? Am I approaching the problem from the wrong side?
P.S. I do not use library functions to find min and max because I am learning the mechanics of the language. Thanks for your patience.
You can take the first item in the list to be the min or max value and then recurse down the rest of the list comparing as you are going. For example:
let myMax items =
match items with
| [] -> failwith "no data"
| head :: tail ->
let rec recMax maxSoFar items =
match items with
| [] -> maxSoFar
| head :: tail ->
if head > maxSoFar then
recMax head tail
else
recMax maxSoFar tail
recMax head tail
It should be System.Int32.MaxValue but also note you should use System.Int32.MinValue for findMax in order to make it work properly with negatives.
I'm messing around with F# and Fable, and trying to test my understanding. To do so, I tried creating a function to calculate e given a certain number of iterations. What I've come up with is
let eCalc n =
let rec internalECalc ifact sum count =
match count = n with
| true -> sum
| _ -> internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1
Which works fine, returning 2.7182818284590455 when called with
eCalc 20
However, if I try using, what I think is, the more correct form
let eCalc n =
let rec internalECalc ifact sum count =
match count with
| n -> sum
| _ -> internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1
I get a warning "[WARNING] This rule will never be matched (L5,10-L5,11)", and returned value of 0. (and the same thing happens if I swap 'n' and 'count' in the match statement). Is there a reason I can't use 'n' in the match statement? Is there a way around this so I can use 'n'?
Thanks
When you use a name in a match statement, you're not checking it against the value assigned to that variable the way you think you are. You are instead assigning that name. I.e.,
match someInt with
| n -> printfn "%d" n
will print the value of someInt. It's the equivalent of let n = someInt; printfn "%d" n.
What you wanted to do was use a when clause; inside a when clause, you're not pattern-matching, but doing a "standard" if check. So what you wanted was:
let eCalc n =
let rec internalECalc ifact sum count =
match count with
| cnt when cnt = n -> sum
| _ -> internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1
Does that make sense, or do you need me to go into more detail?
P.S. In a case like this one where your match function looks like "x when (boolean condition involving x) -> case 1 | _ -> case 2", it's quite a bit more readable to use a simple if expression:
let eCalc n =
let rec internalECalc ifact sum count =
if count = n then
sum
else
internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1
I'm trying to create an infinite Stream in F# that contains armstrong numbers. An armstrong number is one whose cubes of its digits add up to the number. For example, 153 is an armstrong number because 1^3 + 5^3 + 3^3 = 153. so far, I have created several functions to help me do so. They are:
type 'a stream = Cons of 'a * (unit -> 'a stream);;
let rec upfrom n = Cons (n, fun() -> upfrom (n+1));;
let rec toIntArray = function
| 0 -> []
| n -> n % 10 :: toIntArray (n / 10);;
let rec makearmstrong = function
| [] -> 0
| y::ys -> (y * y * y) + makearmstrong ys;;
let checkarmstrong n = n = makearmstrong(toIntArray n);;
let rec take n (Cons(x,xsf)) =
match n with
| 0 -> []
| _ -> x :: take (n-1)(xsf());;
let rec filter p (Cons (x, xsf)) =
if p x then Cons (x, fun() -> filter p (xsf()))
else filter p (xsf());;
And finally:
let armstrongs = filter (fun n -> checkarmstrong n)(upfrom 1);;
Now, when I do take 4 armstrongs;;, (or any number less than 4) this works perfectly and gives me [1;153;370;371] but if I do take 5 armstrongs;;nothing happens, it seems like the program freezes.
I believe the issue is that there are no numbers after 407 that are the sums of their cubes (see http://oeis.org/A046197), but when your code evaluates the equivalent of take 1 (Cons(407, filter checkarmstrong (upfrom 408))) it's going to force the evaluation of the tail and filter will recurse forever, never finding a matching next element. Also note that your definition of Armstrong numbers differs from, say, Wikipedia's, which states that the power the digits are raised to should be the number of digits in the number.