I'm new to F# and I'm making a program that requires finding every sub-list of given length of some list. I wasn't sure how to go about this so I read this question and decided to port the answer to F#. Here's what I have:
let rec getSubLists (len : int) (list : List<int>) : List<List<int>> =
let result = new List<List<int>>()
let current = new List<int>()
let rec findSubLists (len : int) (superSet : List<int>) (current : List<int>) (soln : List<List<int>>) (idx : int) : unit =
if current.Length = len then soln.Insert(len - 1, current)
elif idx = superSet.Length then
let x = superSet.[idx]
current.Insert(len, x)
findSubLists len superSet current soln (idx + 1)
current.RemoveAt(x)
findSubLists len superSet current soln (idx + 1)
else ()
findSubLists len list current result 0
result
The compiler is upset about a few things: it says there is no constructor for List<int>, List<List<int>>, and it says that Insert and RemoveAt are not defined. I found these methods in the microsoft docs. This tutorial mentions RemoveAt, but it uses Add instead of Insert, which also didn't work.
In F# the type List<'t> is the immutable F# list. It is not the same as System.Collections.Generic.List<T>, which is what is described in the docs you linked.
To access the latter, either open the System.Collections.Generic namespace (but beware: this will shadow the regular F# list) or refer to it by its F# alias, ResizeArray<'t>, which also better expresses its true nature.
let rec getSubLists (len : int) (list : ResizeArray<int>) : ResizeArray<ResizeArray<int>> =
let result = new ResizeArray<ResizeArray<int>>()
let current = new ResizeArray<int>()
let rec findSubLists (len : int) (superSet : ResizeArray<int>) (current : ResizeArray<int>) (soln : ResizeArray<ResizeArray<int>>) (idx : int) : unit =
if current.Count = len then soln.Insert(len - 1, current)
elif idx = superSet.Count then
let x = superSet.[idx]
current.Insert(len, x)
findSubLists len superSet current soln (idx + 1)
current.RemoveAt(x)
findSubLists len superSet current soln (idx + 1)
else ()
findSubLists len list current result 0
result
(also note that it's Count, not Length)
Related
The compiler returns a Syntax error when using the command in
xyz aux
if((match4242 aux) = 0) then main (!list) else 1
Here's my full code.
open Printf
open Format
let regraUm m = m/2
let regraDois m = ((m / 10) mod 10) * (m mod 10)
let regraTres m = 42
let match4242 list =
let a = ref 0 in
let rec match42 list =
match list with
|[]->[]
|m::body->
begin
if (m = 42) then a := 1;
match42 body
end
in match42 list;
!a
let rec main aux =
let list = ref [] in
let rec xyz aux =
let () = List.iter (fun x -> printf "%d " x) aux in
match aux with
|[]->[]
|m::body ->
begin
if ((m mod 2) = 0) then list := (m - (regraUm m))::!list;
if ((m mod 3) = 0) || ((m mod 4) = 0) then
if (regraDois m <> 0) then
list := (m - (regraDois m)) ::!list;
if ((m mod 5) = 0) then list := (m - (regraTres m))::!list;
xyz body
end
in xyz aux
if((match4242 aux) = 0) then main (!list) else 1
The program checks if 42 is inside the list, if not then it calls itself again following a set of rules of division, subtraction, etc.
I don't know if this last info is helpful to debug this piece of code.
These two lines:
xyz aux
if ((match4242 aux) = 0) then main (!list) else 1
Represent a single expression, since they aren't separated by ;. But indeed you can't have an if expression in this position (function argument) unless you parenthesize it.
Most likely you want ; after aux here.
Im new to f# and i'm trying to make this exercise:
"Implement a function"
let rec nth(n : int) (l : List<'a>) : Option<'a> =
that returns the element in position n in l. The function must handle appropriately the case where the index is invalid
this is my current code but I'm kinda stuck:
let rec nth (n : int) (l : List<'a>) : Option<'a> =
if n > l.Length then
None
else
match l with
| [] -> None
Thanks for the help!
There is a built-in function List.tryItem
let rec nth(n : int) (l : List<'a>) : Option<'a> =
l |> List.tryItem n
Can you use any functionality provided by the core library at all? If so, I suggest the following function:
let nth (n : int) (l : 'a list) : 'a option =
if n < 1 || n > l.Length then None else Some l.[n - 1]
This just checks whether the index is within permitted boundaries, then returns the element at the appropriate index. The index-item operator is zero-based, therefore we need to subtract one from the number passed into the function, and the list iteration is done by the compiler behind the scenes.
If you need to do it completely manually, I suggest the following function:
let nth (n : int) (l : 'a list) : 'a option =
let rec inner i = function
| [] -> None
| x :: _ when i = 0 -> Some x
| _ :: xs -> inner (i - 1) xs
if n < 1 then None else inner (n - 1) l
This checks the lower boundary, and if it is all right, starts to iterate the list using an inner function, and decrementing the index until it is zero so it knows it reached the right index. If the list is shorter, None is returned.
This F# code is an attempt to solve Project Euler problem #58:
let inc = function
| n -> n + 1
let is_prime = function
| 2 -> true
| n when n < 2 || n%2=0-> false
| n ->
[3..2..(int (sqrt (float n)))]
|> List.tryFind (fun i -> n%i=0)
|> Option.isNone
let spir = Seq.initInfinite (fun i ->
let n = i%4
let a = 2 * (i/4 + 1)
(a*n) + a + (a-1)*(a-1))
let rec accum se p n =
match se with
| x when p*10 < n && p <> 0 -> 2*(n/4) + 1
| x when is_prime (Seq.head x) -> accum (Seq.tail x) (inc p) (inc n)
| x -> accum (Seq.tail x) p (inc n)
| _ -> 0
printfn "%d" (accum spir 0 1)
I do not know the running time of this program because I refused to wait for it to finish. Instead, I wrote this code imperatively in C++:
#include "stdafx.h"
#include "math.h"
#include <iostream>
using namespace std;
int is_prime(int n)
{
if (n % 2 == 0) return 0;
for (int i = 3; i <= sqrt(n); i+=2)
{
if (n%i == 0)
{
return 0;
}
}
return 1;
}
int spir(int i)
{
int n = i % 4;
int a = 2 * (i / 4 + 1);
return (a*n) + a + ((a - 1)*(a - 1));
}
int main()
{
int n = 1, p = 0, i = 0;
cout << "start" << endl;
while (p*10 >= n || p == 0)
{
p += is_prime(spir(i));
n++; i++;
}
cout << 2*(i/4) + 1;
return 0;
}
The above code runs in less than 2 seconds and gets the correct answer.
What is making the F# code run so slowly? Even after using some of the profiling tools mentioned in an old Stackoverflow post, I still cannot figure out what expensive operations are happening.
Edit #1
With rmunn's post, I was able to come up with a different implementation that gets the answer in a little under 30 seconds:
let inc = function
| n -> n + 1
let is_prime = function
| 2 -> true
| n when n < 2 || n%2=0-> false
| n ->
[3..2..(int (sqrt (float n)))]
|> List.tryFind (fun i -> n%i=0)
|> Option.isNone
let spir2 =
List.unfold (fun state ->
let p = fst state
let i = snd state
let n = i%4
let a = 2 * (i/4 + 1)
let diag = (a*n) + a + (a-1)*(a-1)
if p*10 < (i+1) && p <> 0 then
printfn "%d" (2*((i+1)/4) + 1)
None
elif is_prime diag then
Some(diag, (inc p, inc i))
else Some(diag, (p, inc i))) (0, 0)
Edit #2
With FuleSnabel's informative post, his is_prime function makes the above code run in under a tenth of a second, making it faster than the C++ code:
let inc = function
| n -> n + 1
let is_prime = function
| 1 -> false
| 2 -> true
| v when v % 2 = 0 -> false
| v ->
let stop = v |> float |> sqrt |> int
let rec loop vv =
if vv <= stop then
if (v % vv) <> 0 then
loop (vv + 2)
else
false
else
true
loop 3
let spir2 =
List.unfold (fun state ->
let p = fst state
let i = snd state
let n = i%4
let a = 2 * (i/4 + 1)
let diag = (a*n) + a + (a-1)*(a-1)
if p*10 < (i+1) && p <> 0 then
printfn "%d" (2*((i+1)/4) + 1)
None
elif i <> 3 && is_prime diag then
Some(diag, (inc p, inc i))
else Some(diag, (p, inc i))) (0, 0)
There is no Seq.tail function in the core F# library (UPDATE: Yes there is, see comments), so I assume you're using the Seq.tail function from FSharpx.Collections. If you're using a different implementation of Seq.tail, it's probably similar -- and it's almost certainly the cause of your problems, because it's not O(1) like you think it is. Getting the tail of a List is O(1) because of how List is implemented (as a series of cons cells). But getting the tail of a Seq ends up creating a brand new Seq from the original enumerable, discarding one item from it, and returning the rest of its items. When you go through your accum loop a second time, you call Seq.tail on that "skip 1 then return" seq. So now you have a Seq which I'll call S2, which asks S1 for an IEnumerable, skips the first item of S1, and returns the rest of it. S1, when asked for its first item, asks S0 (the original Seq) for an enumerable, skips its first item, then returns the rest of it. So for S2 to skip two items, it had to create two seqs. Now on your next run through when you ask for the Seq.tail of S2, you create S3 that asks S2 for an IEnumerable, which asks S1 for an IEnumerable, which asks S0 for an IEnumerable... and so on. This is effectively O(N^2), when you thought you were writing an O(N) operation.
I'm afraid I don't have time right now to figure out a solution for you; using List.tail won't help since you need an infinite sequence. But perhaps just knowing about the Seq.tail gotcha is enough to get you started, so I'll post this answer now even though it's not complete.
If you need more help, comment on this answer and I'll come back to it when I have time -- but that might not be for several days, so hopefully others will also answer your question.
Writing performant F# is very possible but requires some knowledge of patterns that have high relative CPU cost in a tight loop. I recommend using tools like ILSpy to find hidden overhead.
For instance one could imagine F# exands this expression into an effective for loop:
[3..2..(int (sqrt (float n)))]
|> List.tryFind (fun i -> n%i=0)
|> Option.isNone
However it currently doesn't. Instead it creates a List that spans the range using intrinsic operators and passes that to List.tryFind. This is expensive when compared to the actual work we like to do (the modulus operation). ILSpy decompiles the code above into something like this:
public static bool is_prime(int _arg1)
{
switch (_arg1)
{
case 2:
return true;
default:
return _arg1 >= 2 && _arg1 % 2 != 0 && ListModule.TryFind<int>(new Program.Original.is_prime#10(_arg1), SeqModule.ToList<int>(Operators.CreateSequence<int>(Operators.OperatorIntrinsics.RangeInt32(3, 2, (int)Math.Sqrt((double)_arg1))))) == null;
}
}
These operators aren't as performant as they could be (AFAIK this is currently being improved) but no matter how effecient allocating a List and then search it won't beat a for loop.
This means the is_prime is not as effective as it could be. Instead one could do something like this:
let is_prime = function
| 1 -> false
| 2 -> true
| v when v % 2 = 0 -> false
| v ->
let stop = v |> float |> sqrt |> int
let rec loop vv =
if vv <= stop then
(v % vv) <> 0 && loop (vv + 2)
else
true
loop 3
This version of is_prime relies on tail call optimization in F# to expand the loop into an efficient for loop (you can see this using ILSpy). ILSpy decompile the loop into something like this:
while (vv <= stop)
{
if (_arg1 % vv == 0)
{
return false;
}
int arg_13_0 = _arg1;
int arg_11_0 = stop;
vv += 2;
stop = arg_11_0;
_arg1 = arg_13_0;
}
This loop doesn't allocate memory and is just a rather efficient loop. One see some non-sensical assignments but hopefully the JIT:er eliminate those. I am sure is_prime can be improved even further.
When using Seq in performant code one have to keep in mind it's lazy and it doesn't use memoization by default (see Seq.cache). Therefore one might easily end up doing the same work over and over again (see #rmunn answer).
In addition Seq isn't especially effective because of how IEnumerable/IEnumerator are designed. Better options are for instance Nessos Streams (available on nuget).
In case you are interested I did a quick implementation that relies on a simple Push Stream which seems decently performant:
// Receiver<'T> is a callback that receives a value.
// Returns true if it wants more values, false otherwise.
type Receiver<'T> = 'T -> bool
// Stream<'T> is function that accepts a Receiver<'T>
// This means Stream<'T> is a push stream (as opposed to Seq that uses pull)
type Stream<'T> = Receiver<'T> -> unit
// is_prime returns true if the input is prime, false otherwise
let is_prime = function
| 1 -> false
| 2 -> true
| v when v % 2 = 0 -> false
| v ->
let stop = v |> float |> sqrt |> int
let rec loop vv =
if vv <= stop then
(v % vv) <> 0 && loop (vv + 2)
else
true
loop 3
// tryFind looks for the first value in the input stream for f v = true.
// If found tryFind returns Some v, None otherwise
let tryFind f (s : Stream<'T>) : 'T option =
let res = ref None
s (fun v -> if f v then res := Some v; false else true)
!res
// diagonals generates a tuple stream of all diagonal values
// The first value is the side length, the second value is the diagonal value
let diagonals : Stream<int*int> =
fun r ->
let rec loop side v =
let step = side - 1
if r (side, v + 1*step) && r (side, v + 2*step) && r (side, v + 3*step) && r (side, v + 4*step) then
loop (side + 2) (v + 4*step)
if r (1, 1) then loop 3 1
// ratio computes the streaming ratio for f v = true
let ratio f (s : Stream<'T>) : Stream<float*'T> =
fun r ->
let inc r = r := !r + 1.
let acc = ref 0.
let count = ref 0.
s (fun v -> (inc count; if f v then inc acc); r (!acc/(!count), v))
let result =
diagonals
|> ratio (snd >> is_prime)
|> tryFind (fun (r, (_, v)) -> v > 1 && r < 0.1)
I'm writing a code that can find the median of a list, and I cannot use rec and should use List.fold_left/right. I wrote the following code, which should work.
It finds the length of the list, if it's an odd number like 5, then it sets len1, len2 to 2, 3, if it's an even number like 6, then it sets len1, len2 to 2, 3.
Then for each member in the list I match the number of those elements that are less than it.
However, the following pattern matching always math lessNum elmt to len1 - can someone tell me why it is so?
let median (lst : int list) : float option =
let len = List.length lst in
if lst = [] then None
else
let len1, len2 = (len - 1) / 2, (len + 1) / 2 in
let lessNum a =
List.length (List.find_all (fun n -> n < a) lst) in
let answer = List.fold_left (fun accm elmt ->
match (lessNum elmt) with
| len1 -> accm + elmt
| len2 -> failwith "len2"
| _ -> failwith "other"
) 0 lst in
if len mod 2 = 0
then Some ((float_of_int answer) /. 2.0)
else Some (float_of_int answer)
An identifier appearing in a pattern always matches, and binds the corresponding value to the identifier. Any current value of the identifier doesn't matter at all: the pattern causes a new binding, i.e., it gives a new value to the identifier (just inside the match).
# let a = 3;;
val a : int = 3
# match 5 with a -> a;;
- : int = 5
# a;;
- : int = 3
#
So, your match statement isn't doing what you think it is. You'll probably have to use an if for that part of your code.
Update
Here's how to use an association list to approximate the function f in your followup question:
let f x = List.assoc x [(pat1, ans1); (pat2, ans2)]
This will raise a Not_found exception if x is not equal to pat1 or pat2.
(I think your Python code is missing return.)
I'm having a bit difficulty figuring out, how to get each of the processed chars back to an int value.
The function should work like: val caesar = fn : int * int -> int
So if k = 2466 and n = 2, then the output should be 4688
Hope the code isn't too weird (I'm a SML newbie).
(* Load Libs *)
load "Int";
load "Real";
load "String";
load "Char";
load "List";
fun caesar (k, n) =
let
fun k_string (i) = Int.toString(i)
fun item_k_char (x, y) = Char.ord (List.nth (x, y))
val val_k_string = k_string(k)
val k_explode = String.explode(val_k_string)
val counter = ref 0
val counter_end = (String.size(val_k_string) - 1)
in
while (!counter >= counter_end) do (
item_k_char(k_explode, !counter) + n;
counter := !counter + 1
)
end;
A while loop isn't the best tool here. Instead you can use map which executes a given function for each item in a given list and returns a new list containing the result of each call to the function.
In other words: map (fn c => (Char.ord c) + 2) [#"2", #"4", #"6", #"6"] will return [52,54,56,56]. You can the convert this back to char and use String.implode to get the string "4688".
You probably also want to add some logic so that the numbers "wrap around", i.e. caesar (7,7) becomes 4.
So all in all your code becomes:
fun caesar (k, n) =
let
val val_k_string = Int.toString k
val k_explode = String.explode val_k_string
val ints = map (fn c => (Char.ord c) + n) k_explode
val wrappedAroundInts = map (fn i => (i - 48) mod 10 + 48) ints
val chars = map Char.chr wrappedAroundInts
val string = String.implode chars
in
Option.valOf (Int.fromString string)
end