Reputation: 273
I'm writing some thing really easy, a program that finds all factors of an int. Here is what I have
let factor n=
let ls=[]
for i=1 to n do
if i % n =0 then ls = i::ls
l
If I do this then it pops an error This expression was expected to have the type unit. But I tried to put an expression that prints something after if..then.., which is suppose to return type unit, but it still gives the same error. I am lost about this. Can someone help please? Thanks
Upvotes: 0
Views: 124
Reputation: 62975
=
is comparison, not assignment. You want either
let factor n =
let mutable ls = []
for i = 1 to n do
if n % i = 0 then ls <- i::ls
ls
or
let factor n =
let ls = ref []
for i = 1 to n do
if n % i = 0 then ls := i::(!ls)
!ls
Note, however, that both of these solutions are highly unidiomatic, as there are equally easy immutable solutions to this problem.
Upvotes: 1
Reputation: 14468
You are trying to make ls
into a mutable variable nd assign it with =
. While this is possible, by using mutable
(1) or ref
(2) along with <-
or :=
assignment operators, this is generally discouraged in the functional world.
A possibly more idiomatic implementation of the naive algorithm could be:
let factor n =
let rec factorLoop curr divs =
if curr > n then divs
else
if n % curr = 0
then factorLoop (curr+1) (curr::divs)
else factorLoop (curr+1) divs
factorLoop 1 [] |> List.rev
> factor 12;;
val it : int list = [1; 2; 3; 4; 6; 12]
Here the main function defines an inner factorLoop
function that is recursive. Recursion is the way we can avoid many uses of mutable variables in functional languages. The recursive inner function threads along a curr
variable that is the current divisor to be tested and a list divs
of currently found divisors. The result includes 1
and n
. This can be altered respectively by changing the initial value of curr
and the terminating condition in the first line of factorLoop
.
It is worth noting that it can all be shrunk down to one line by making use of the F# library:
let factor n =
[1..n] |> List.filter (fun x -> n % x = 0)
Here we build a list of values 1..n
and feed them to List.filter
which applies the given predicate (at the end of the line) to select only divisors on n
. If n
is large, however, the temp list will grow very large. We can use a lazily evaluated sequence instead, which won't blow the memory usage:
let factor n =
{1..n} |> Seq.filter (fun x -> n % x = 0) |> Seq.toList
Here we filter on a 'lazy' sequence and only convert the (much smaller) sequence of results to a list at the end:
> factor 10000000;;
val it : int list =
[1; 2; 4; 5; 8; 10; 16; 20; 25; 32; ... etc
Upvotes: 2