nested list in F# - f#

I am not sure if this is a stupid question, but I was doing some simple problems on lists in F#. I am unable to handle nested lists. My question is, Why I can't pass a nested list when I have declared a list as parameter of a function? I mean the nested list is also a list. What is the advantage of differentiating lists of simple int or char from lists of lists?

If a function is generic and takes a parameter 'a list, the type of 'a could also be a list. So the function would work with lists, or lists of lists, or lists of lists of lists, ...so long as the outer type is a list, 'a could be anything.
For example:
let isNonEmpty = function
| [] -> false
| _::_ -> true
isNonEmpty [1; 2; 3]
isNonEmpty [[1]; [2]; [3]]
If your function doesn't depend on the list elements being of a certain type it should probably be generic. If you post your code perhaps someone can help with that.
EDIT
A naive version of your flatten function, without using built-in functions, might be:
let flatten lst =
let rec helper = function
| [] -> []
| h::tl ->
match h with
| Elem x -> x::helper tl
| List xs -> helper xs # helper tl
helper [lst]

If you have a function requiring a list<char> and you have a list<list<char>> those types don't match. However, there is a function List.concat which will "flatten" the list of lists.
So:
let list = [ ['a'] ; ['b'] ]
let list' = list |> List.concat // [ 'a' ; 'b' ]

For anyone who is looking for more of a dynamically typed nested list behavior, you should take a look at my NestedPair module:
https://gist.github.com/calebh/45871d3d40dc93526b3fd227cd577467
This module allows for "lists" of arbitrary depth by using a simple wrapper type.

Related

Why does F# not like the type ('a list list) as input?

*I edited my original post to include more info.
I'm working on an F# assignment where I'm supposed to create a function that takes an "any list list" as input and outputs an "any list". It should be able to concatenate a list of lists into a single list.
Here's what my function looks like:
let llst = [ [1] ; [2;3] ; ['d';'e';'f'] ]
let concat (llst:'a list list) : 'a list =
List.concat llst
List.iter (fun elem -> printf "%d " elem) concat
This solution more or less copied directly from microsofts example of using the List.concat function, the only exception being the specification of input/output types.
When i run the code i get this error:
concat.fsx(7,43): error FS0001: This expression was expected to have type
''a list'
but here has type
''b list list -> 'b list'
So it appears that concat is turning my llst into a character list, which i don't understand.
Can anyone help me understand why I'm getting this type error and how I can write a function that takes the types that I need?
The problem is somewhere in your implementation of the concat function. It is hard to say where exactly without seeing your code, but since this is an assignment, it is actually perhaps better to explain what the error message is telling you, so that you can find the issue yourself.
The error message is telling you that the F# type inference algorithm found a place in your code where the actual type of what you wrote does not match the type that is expected in that location. It also tells you what the two mismatching types are. For example, say you write something like this:
let concat (llst:'a list list) : 'a list =
llst
You will get the error you are getting on the second line, because the type of llst is 'a list list (the compiler knows this from the type annotation you give on line 1), but the expected type is the same as the result type of the function which is 'a list - also specified by your type annotation.
So, to help you find the issue - look at the exact place where you are getting an error and try to infer why compiler thinks that the actual type is 'a list list and try to understand why it expects 'a list as the type that should be in this place.
This is correct:
let concat (llst:'a list list) : 'a list =
List.concat llst
However, it's really equivalent to let concat = List.concat
This, however, doesn't compile, the elements of the lists need to be of the same type:
let llst = [ [1] ; [2;3] ; ['d';'e';'f'] ]
This also is problematic:
List.iter (fun elem -> printf "%d " elem) concat
List.iter has two arguments and the second one needs to be a List. However in your case you are (as per compiler error) providing your concat function which is a a' List List -> a' List.
What I suspect you meant to do, is apply the concat function to your llist first:
List.iter (fun elem -> printf "%d " elem) (concat llist)
// or
llist
|> concat
|> List.iter (fun elem -> printf "%d " elem)
However, all of this is perhaps missing the point of the exercise. What perhaps you need to do is implement some simple recursion based on the empty / non-empty state of your list, ie. fill in the blanks from here:
let rec myconcat acc inlist =
match inlist with
| [] -> ??
| elt :: tail -> ??

Noob question about F# function parameter where the parameter is a list

I'm trying to play around with creating functions in F#, In the image below, I'm trying to create a function that takes a list of floats and sum the values in the list. I don't know how to pass a list as parameter in a function so I tried this to get the head of a list but the code doesn't work:
let sumlist l=
printf "%f" l.Head
Then I see some people does:
let sumlist l:float=
match l with
| [] -> 0.0
| e::li -> e + sumlist li
So is l:float the way you pass a list to a function? so like l:string would be a list of string?
But I saw list l has l.Head function to return the first element in the list(As it seems that we can't access arbitrary elements in the list like an array) but
let sumlist l:float=
printfn "%f" l.Head
gives type mismatch error.
I also don't understand the recursive code provided, I don't understand this line
| e::li -> e + sumlist li
What is ::? and Li?
Thank you for clarifying this for me!
So your first example doesn't return anything and that's because you're calling printfn which prints to the console instead of returning your types. e :: li here represents a list where e is the head and li is the rest of the list. The :: here lets the compiler know that you want to deconstruct the list.
//fully annotated
let s (l: float list) :float =
l.Head
//here the types can be inferred without any annotation
let rec sumlist l =
match l with
| [] -> 0.0
| e::li -> e + sumlist li
s [0.7]
//returns 0.7
sumlist [0.4;0.5;0.6]
//returns 1.5
In my first example if you try and remove the type annotations you'll notice that you get an error. This is because l.Head's type is ambiguous otherwise did you call l.Head on a list of strings, floats? In the sumlist function I provided you can see that I didn't need to annotate, and this is because I'm adding them up and that constrains the types.
Personally when starting I highly recommend always annotating the types. (l : float list) or (l: list<float>) is a way to say my input is a list of floats, and :float at the end how we say the return type is a float. You'll notice I put a rec keyword on our recursive function, it's better to explicitly declare whenever you make a recursive function.
Syntax questions
So is l:float the way you pass a list to a function?
No. Most of the time the compiler can figure out that you are passing a list without annotating the parameter as a list, but when it doesn't, you annotate is
l : 'a list // where 'a is generic type
// OR
l : float list // where type is specified as float
What is ::? and Li?
When pattern matching a list, [] matches to empty list, which here is used as the recursion end criteria. The other match separates head (e) from the rest of the list aka tail (li). If there is only one item in list, then li evaluates as [].
Additional note for your recursive code: You are missing the recursion keyword rec eg.
let rec sumlist ...
Recursive function implementation
The easiest way would be to use the sum function of List eg.
[0.4; 0.5; 0.6] |> List.sum // Returns 1.5
But, if you want to create this function yourself, consider using tail-recursion for better performance and to avoid stack overflow with bigger input lists.
let sumlist (values : float list) =
let rec sum (acc : float) (remaining : float list) =
match remaining with
| [] -> acc
| head :: tail -> sum (acc + head) tail
sum 0. values
Which is called
[0.4; 0.5; 0.6] |> sumlist // Returns 1.5
The difference here to a normal recursion is that each recursion calculates its own values and is not dependent on other recursions yet to come to finish its calculations.

F# How to get value of Some from a list

I have a list of options such as [Some 1; Some 2]. My aim is to get the values of Some elements without using pattern matching and options.get functions.
I have a testfunction which returns ('a -> 'b) option -> 'a option -> 'b option.
To achieve my goal, how can i use this function?
let test xa xb =
match xa with
| None -> None
| Some el -> Option.map el xa
You can get the values of the Some elements with the List.choose function, which does almost exactly that.
[Some 1; Some 2] |> List.choose id
// Returns [1; 2]
The semantics of the List.choose function is that it lets you chose some elements of the list by providing a function, which for every element returns either Some or None. Elements for which the function returns None are discarded, and the Some results are unwrapped and returned as a list. You can think of this function as a combination of map and filter in one.
Because the elements of your list are already of the option type, your choosing function would be id, which is a standard library function that simply returns its argument unchanged.

F# print all element from the list one by one using recursion

Imagine that I have function printList that takes list as an argument and prints all the elements in the list one by one in a new row followed by the position in the list also while having space between them.
E.G
1: 4
2: 9
3: 12
How can I implement this in F# using recursion without any built-in features ?
I assume it might look something like this, but I've problems with int, unit types.
let rec printList l = function
match l with
| [] -> 0
| head::tail -> // something
There are two advices I can give you so you can implement the printList function:
you will have to make printList a non-recursive function and define a local recursive helper function in order to keep track of the index of the value.
all branches of your match expression must return the same type and here what you want is the unit type.
In case you are still stuck, I provide the solution below.
Solution
let printList list =
let rec helper index list =
match list with
| [] -> ()
| head :: tail ->
printfn "%d: %A" index head
helper (index + 1) tail
helper 1 list

How does the implementation of list in F# work?

I'm curious as to how the list module/type works in F#, specifically does it optimise this?
let xs = ["1"; "2"; "3"]
let ys = "0"::xs
let zs = ["hello"; "world"]#xs
I've looked over some of the source https://github.com/fsharp/fsharp/blob/68e37d03dfc15f8105aeb0ac70b846f82b364901/src/fsharp/FSharp.Core/prim-types.fs#L3493 seems to be the relevant area.
I would like to know if xs is copied when making ys.
I would have thought it's easy to just point to the existing list if you just cons element.
If you are concatenating I imagine it might be impossible as it would require mutating the last element of the list to point to the next one?
If someone could annotate/paste snippets of code from FSharp.Core that would be ideal.
So the implementation of List is a little odd. It is actually implemented as a discriminated union. From the spec:
type 'T list =
| ([])
| (::) of 'T * 'T list
So you can think of :: as a function that takes two arguments and creates a tuple (which is fast as it is independent of the list size).
# is much more complicated. Here is the implementation:
let (#) l1 l2 =
match l1 with
| [] -> l2
| (h::t) ->
match l2 with
| [] -> l1
| _ ->
let res = [h]
let lastCons = PrivateListHelpers.appendToFreshConsTail res t
PrivateListHelpers.setFreshConsTail lastCons l2;
res
The two weird functions basically mutate the list in place. appendToFreshConsTail copies the list and returns the last element. setFreshConsTail then changes the last element so that its next element is set to l2 rather than [] joining the lists.

Resources