I have an exercise that asks me to make a recursive function that uses # to create a list of [1;2;3..n]. Unfortunately I cannot get this method to work.
let lstInt: int list = []
let rec oneToN (n:int) : int list =
let addList = [n]
match n with
0 ->
lstInt
|_ ->
lstInt#addList
oneToN (n-1)
I have tried making my list mutable, but that doesn't seem to actually matter nor make much sense as you can still add and remove elements from lists in f# even though it is not mutable.
I have also tried removing space between # but that shouldn't matter either.
Edit: I should clarify, the issue is the lstInt#addList, which gives me the error:
"The result of this expression has type 'int list' and is implicitly ignored. Consider using 'ignore' to discard this value explicitly, e.g. 'expr |> ignore', or 'let' to bind the result to a name, e.g. 'let result = expr"
That warning is not the issue, but it points you to the issue: you're creating a new list which is a concatenation of an empty list and [n], but then you're doing nothing with that new list. It's just dropped on the floor.
After that, you proceed to call oneToN (n-1) recursively and return its result. At the end of recursion, the very last call to oneToN will ultimately return an empty list, and that will be the return value of every previous iteration, since every iteration (except the last one) returns whatever the next iteration returns.
What you need to do is call oneToN (n-1), which will give you a list of numbers from 1 to n-1, and then append [n] to that list. And the result of that appending would be your return value: after all, if you take a list of numbers from 1 to n-1 and attach n to the end of it, you'll get a list of numbers from 1 to n.
let rec oneToN (n:int) : int list =
let addList = [n]
match n with
0 ->
lstInt
|_ ->
(oneToN (n-1)) # addList
Right now I have a few instances like this:
let doIt someList =
if someList |> List.truncate 2 |> List.length >= 2 then
someList[0] + someList[1]
else
0
I need to grab the top 2 elements of a list quite often to see changes, but in some cases I don't have enough elements and I need to make sure there are at least 2.
The best way I've found so far is to truncate the list before getting its length, but this creates allocations for no reason.
Is there a better method?
I think I would suggest pattern matching in this case:
let doIt someList =
match someList with
| a :: b :: _ -> a + b
| _ -> 0
Here, a and b are the ints in the list, while _ represents a discarded of list int. This way you don't have to pull the first two elements out of the list with an index, as they are already available as a and b. The last case of the match catches any pattern that was not matched earlier, such as cases with zero, one or three-or-more elements.
This should be a cheap operation, as F# lists are implemented as a singly linked list. So [a;b;c;d] would be represented as a::(b::(c::(d::[]))). a and b are matched, while the rest (c::(d::[])) is left untouched (and is put in the _ slot). It does not need to create a new list to do so.
I'm trying to do this exercise:
I'm not sure how to use Type in F#, in F# interactive, I wrote type term = Term of float *int, Then I tried to create a value of type term by let x: term = (3.5,8);;But it gives an error.
Then I tried let x: term = Term (3.5,8);; and it worked. So Why is that?
For the first function, I tried:
let multiplyPolyByTerm (x:term, p:poly)=
match p with
|[]->[]
But that gives an error on the line |[]->[] saying that the expression is expecting a type poly, but poly is a in fact a list right? So why is it wrong here? I fixed it by |Poly[]->Poly[]. Then I tried to finish the function by giving the recursive definition of multiplying each term of the polynomial by the given term: |Poly a::af-> This gives an error so I'm stuck on trying to break down the Poly list.
If anyone has suggestion on good readings about Type in F#, please share it.
I got all the methods now, However,I find myself unable to throw an exception when the polynomial is an empty list as the base case of my recursive function is an empty list. Also, I don't know how to group common term together, Please help, Here are my codes:
type poly=Poly of (float*int) list
type term = Term of float *int
exception EmptyList
(*
let rec mergeCommonTerm(p:poly)=
let rec iterator ((a: float,b: int ), k: (float*int) list)=
match k with
|[]->(a,b)
|ki::kf-> if b= snd ki then (a+ fst ki,b)
match p with
|Poly [] -> Poly []
|Poly (a::af)-> match af with
|[]-> Poly [a]
|b::bf -> if snd a =snd b then Poly (fst a +fst b,snd a)::bf
else
*)
let rec multiplyPolyByTerm (x:term, p:poly)=
match x with
| Term (coe,deg) -> match p with
|Poly[] -> Poly []
|Poly (a::af) -> match multiplyPolyByTerm (x,Poly af) with
|Poly recusivep-> Poly ((fst a *coe,snd a + deg)::recusivep)
let rec addTermToPoly (x:term, p:poly)=
match x with
|Term (coe, deg)-> match p with
|Poly[] -> Poly [(coe,deg)]
|Poly (a::af)-> if snd a=deg then Poly ((fst a+coe,deg)::af)
else match addTermToPoly (x,Poly af) with
|Poly recusivep-> Poly (a::recusivep)
let rec addPolys (x:poly, y: poly)=
match x with
|Poly []->y
|Poly (xh::xt)-> addPolys(Poly xt,addTermToPoly(Term xh, y))
let rec multPolys (x:poly,y:poly)=
match x with
|Poly []-> Poly[]
|Poly (xh::xt)->addPolys (multiplyPolyByTerm(Term xh,y),multPolys(Poly xt,y))
let evalTerm (values:float) (termmm : term) :float=
match termmm with
|Term (coe,deg)->coe*(values**float(deg))
let rec evalPoly (polyn : poly, v: float) :float=
match polyn with
|Poly []->0.0
|Poly (ph::pt)-> (evalTerm v (Term ph)) + evalPoly (Poly pt,v)
let rec diffPoly (p:poly) :poly=
match p with
|Poly []->Poly []
|Poly (ah::at)-> match diffPoly (Poly at) with
|Poly [] -> if snd ah = 0 then Poly []
else Poly [(float(snd ah)*fst ah,snd ah - 1)]
|Poly (bh::bt)->Poly ((float(snd ah)*fst ah,snd ah - 1)::bh::bt)
As I mentioned in a comment, reading https://fsharpforfunandprofit.com/posts/discriminated-unions/ will be very helpful for you. But let me give you some quick help to get you unstuck and starting to solve your immediate problems. You're on the right track, you're just struggling a little with the syntax (and operator precedence, which is part of the syntax).
First, load the MSDN operator precedence documentation in another tab while you read the rest of this answer. You'll want to look at it later on, but first I'll explain a subtlety of how F# treats discriminated unions that you probably haven't understood yet.
When you define a discriminated union type like poly, the name Poly acts like a constructor for the type. In F#, constructors are functions. So when you write Poly (something), the F# parser interprets this as "take the value (something) and pass it to the function named Poly". Here, the function Poly isn't one you had to define explicitly; it was implicitly defined as part of your type definition. To really make this clear, consider this example:
type Example =
| Number of int
| Text of string
5 // This has type int
Number 5 // This has type Example
Number // This has type (int -> Example), i.e. a function
"foo" // This has type string
Text "foo" // This has type Example
Text // This has type (string -> Example), i.e. a function
Now look at the operator precedence list that you loaded in another tab. Lowest precedence is at the top of the table, and highest precedence is at the bottom; in other words, the lower something is on the table, the more "tightly" it binds. As you can see, function application (f x, calling f with parameter x) binds very tightly, more tightly than the :: operator. So when you write f a::b, that is not read as f (a::b), but rather as (f a)::b. In other words, f a::b reads as "Item b is a list of some type which we'll call T, and the function call f a produces an item of type T that should go in front of list b". If you instead meant "take the list formed by putting item a at the head of list b, and then call f with the resulting list", then that needs parentheses: you have to write f (a::b) to get that meaning.
So when you write Poly a::af, that's interpreted as (Poly a)::af, which means "Here is a list. The first item is a Poly a, which means that a is a (float * int) list. The rest of the list will be called af". And since the value your passing into it is not a list, but rather a poly type, that is a type mismatch. (Note that items of type poly contain lists, but they are not themselves lists). What you needed to write was Poly (a::af), which would have meant "Here is an item of type poly that contains a list. That list should be split into the head, a, and the rest, af."
I hope that helped rather than muddle the waters further. If you didn't understand any part of this, let me know and I'll try to make it clearer.
P.S. Another point of syntax you might want to know: F# gives you many ways to signal an error condition (like an empty list in this assignment), but your professor has asked you to use exception EmptyList when invalid input is given. That means he expects your code to "throw" or "raise" an exception when you encounter an error. In C# the term is "throw", but in F# the term is "raise", and the syntax looks like this:
if someErrorCondition then
raise EmptyList
// Or ...
match listThatShouldNotBeEmpty with
| [] -> raise EmptyList
| head::rest -> // Do something with head, etc.
That should take care of the next question you would have needed to ask. :-)
Update 2: You've edited your question to clarify another issue you're having, where your recursive function boils down to an empty list as the base case — yet your professor asked you to consider an empty list as an invalid input. There are two ways to solve this. I'll discuss the more complicated one first, then I'll discuss the easier one.
The more complicated way to solve this is to have two separate functions, an "outer" one and an "inner" one, for each of the functions you have been asked to define. In each case, the "outer" one checks whether the input is an empty list and throws an exception if that's the case. If the input is not an empty list, then it passes the input to the "inner" function, which does the recursive algorithm (and does NOT consider an empty list to be an error). So the "outer" function is basically only doing error-checking, and the "inner" function is doing all the work. This is a VERY common approach in professional programming, where all your error-checking is done at the "edges" of your code, while the "inner" code never has to deal with errors. It's therefore a good approach to know about — but in your particular case, I think it's more complicated than you need.
The easier solution is to rewrite your functions to consider a single-item list as the base case, so that your recursive functions never go all the way to an empty list. Then you can always consider an empty list to be an error. Since this is homework I won't give you an example based on your actual code, but rather an example based on a simple "take the sum of a list of integers" exercise where an empty list would be considered an error:
let rec sumNonEmptyList (input : int list) : int =
match input with
| [] -> raise EmptyList
| [x] -> x
| x::rest -> x + sumNonEmptyList rest
The syntax [x] in a match expression means "This matches a list with exactly one item in it, and assigns the name x to the value of that item". In your case, you'd probably be matching against Poly [] to raise an exception, Poly [a] as the base case, and Poly (a::af) as the "more than one item" case. (That's as much of a clue as I think I should give you; you'll learn better if you work out the rest yourself).
I am attempting to create a function to pattern match a structure which is a tuple containing a value and a list of tuples of the form
'a * ('b * 'c) list -> 'b list
for example given the following:
let clubDetails = ("MyClub", [("Secretary", "Jill");("Captain", "Bob");("Email", "Bob#MyClub.com")])
I need a function to return the list ["Secretary";"Captain";"Email"]
So I thought I could do something like this :
let getClubAttributes ca =
match ca with
| (a, [(b,c)]) -> [b]
| _ -> []
but here
getClubAttributes clubDetails
Returns the empty list. I feel like I am missing something pretty obvious.
Thanks,
Russell.
The pattern match form that you have written will only match if the list in your tuple has exactly one element.
I note that you have written a default _ case in your pattern match which returns the empty list and this is the case you are hitting. I suspect you've added this case to remove the compiler warning but the compiler warning is, in fact, warning you of this exact problem.
You do not actually need a pattern match because your data structure can be handled with only one case.
let clubDetails = ("MyClub", [("Secretary", "Jill");("Captain", "Bob");("Email", "Bob#MyClub.com")])
let getClubAttributes (ca, attribList) =
List.map fst attribList
The new getClubAttributes function simply creates a new list from the original by taking the first element of each item in the list.
Given this tree type:
type T<'a> = N of 'a * T<'a> list
which could be declared as:
let ta = N("b", [N("c", [])])
How would I get all the possible paths in this tree? I've tried by applying the method mentioned in this post, but it just returns an empty list. This is how I've implemented it:
let rec isPath is t =
match t with
| N(x, t) -> List.collect (isPath (x::is)) t
isPath [] ta |> (printf "isPath: %A")
but it only returns isPath: []. What am I doing wrong? My secondary goal would then be to make a second function where I can pass a list of ints to check if there are any paths that correspond to this list.
You need another match condition that catches empty lists and doesn't iterate through them. Right now your List.collect, when t is empty, is iterating through an empty list and is therefore returning an empty list to the "previous" level of your recursive function. Which is then appending all those empty lists together to get... an empty list, and so on.
Add the following match case and you should get what you need:
| N(x, []) -> is
Note that this should come before your other match case in order to work: since F# processes match cases from top to bottom, N(x, t) will match anything, and N(x, []) won't ever be checked if it's second.
So you want your function to look like:
let rec isPath is t =
match t with
| N(x, []) -> is
| N(x, t) -> List.collect (isPath (x::is)) t
Again, if you don't see why this works, let me know and I'll explain further.