Following my previous post here , I tried to do what was suggested and convert the code
into a Tail-recursion method with let .
The original code - which does not work (due to using val inside if condition) :
fun func() =
val decimal = 0 (* the final result *)
val multiple = 0 (* keeps track of multiples, eg. In XXV, X would be a multiple *)
val current = 0 (* the digit currently being processed *)
val top = 0 (* value of the last element in the list *)
val last_add = 0 (* the last digit that wasn't a multiple, or subtraction operation *)
val last_sub = 0
val problem = 0 (* if value is 1 then there is a problem with the input *)
val myList = [1,2,3,4,5] (* the list has more values *)
while (myList <> []) (* run while the list is not empty *)
val current = tl(myList) (* grab the last element from the list *)
val myList = tl(myList) (* remove the last element from the list *)
val top = tl(myList) (* grab the value at the end of the list *)
if ( myList <> []) andalso (current > top))
then
val decimal = decimal + current - top
val last_sub = top;
val myList = tl(myList)
else
if ( (myList = []) andalso (current = top))
then val decimal = decimal + current
val multiple = multiple + 1
else
if (last_sub = current)
then val problem = 1
else
val decimal = decimal + current
val multiple = 0
val last_add = current
And the code as a tail-recursion method :
fun calc [] = 0
|calc [x] = x
|calc (head::tail) =
let
val decimal = 0
val multiple = 0
val current = 0
val top = 0
val last_add = 0
val last_sub = 0
val problem = 0
val doNothing = 0
in
let
val current = hd(rev(head::tail)) (* grab the last element *)
val head::tail = rev(tl(rev(head::tail))) (* POP action - remove the last element from the list *)
val top = hd(rev(head::tail)) (* grab the new last element after removing *)
in
if (current > top) then
let
val decimal = decimal + current - top
val last_sub = top
val head::tail = rev(tl(rev(head::tail))) (* POP action - remove the last element from the list *)
in
calc(head::tail)
end
else
if ( (head::tail = []) andalso (current = top))
then let
val decimal = decimal + current
val multiple = multiple + 1
in
calc(head::tail)
end
else
if (last_sub <> current)
then let
val decimal = decimal + current
val multiple = 0
val last_add = current
in
calc(head::tail)
end
else
(* do nothing *)
val doNothing = 0
end
end;
However , when I try to enter :
calc([0,100,20,30,4,50]);
I get :
uncaught exception Bind [nonexhaustive binding failure]
raised at: stdIn:216.13-216.50
I know the code is very hard to read and pretty long , but it would be greatly appreciated
if someone could explain to me how to fix it , or help me find the reason for this output .
Thanks
You have a few issues with your code.
First of all, you can use last to grab the last element of a list. See the List documentation for more info. But unless you have a really good reason to do so, it's easier and much more efficient to simply start from the beginning of the list and pop elements off the beginning as you recurse. You already have the first element bound to head in your code using pattern matching.
Secondly, unless you use refs (which you probably don't want to do) there are no variables in Standard ML, only values. What this means is that if you want to carry state between invocations, any accumulators need to be parameters of your function. Using a helper function to initialize accumulators is a common pattern.
Third, instead of comparing a list to [] to test if it's empty, use the null function. Trust me on this. You'll get warnings using = because of subtle type inference issues. Better yet, use a pattern match on your function's parameters or use a case statement. Pattern matching allows the compiler to tell you whether you've handled all possible cases.
Fourth, SML typically uses camelCase, not snake_case, for variable names. This is more stylistic, but as you write more code and collaborate, you're going to want to fit with the conventions.
Fifth, when you do recursion on a list, don't try to look at multiple values in the list. This complicates things. Treat it as a head element and tail list, and everything will become much simpler. In my code, instead of keeping current in the list, I did this by splitting it out into a separate parameter. Have a base case where you simply return the answer from one of your accumulators, and a recursive case where you recurse with updated accumulator values and a single value popped from your list. This eliminates the problem scenario.
I'm not sure if this logic is correct since I don't know what you're trying to calculate, but check out this code which illustrates some of the things I talked about.
(* This is the helper function which takes accumulators as
parameters. You shouldn't call this directly. *)
fun calc' decimal _ _ _ _ [] =
(* We processed everything in the list. Just return the accumulator. *)
decimal
| calc' decimal multiple lastAdd lastSub current (top::tail) =
(* This case is for when there are 1 or more elements in the list. *)
if current > top then
calc' (decimal + current - top) multiple lastAdd top top tail
else if current = top then
calc' (decimal + current) (multiple + 1) lastAdd lastSub top tail
else
calc' (decimal + current) 0 current lastSub top tail
(* This is the function you should call. *)
fun calc [] = 0
| calc [_] = 0 (* Given a single-element list. *)
| calc (x::xs) =
(* Apply the helper with correct initial values. *)
calc' 0 0 0 0 x xs
In a functional language, instead of assigning to a variable when you want to change it, simply recurse and specify the new value for the correct parameter. This is how you write a "loop" in a functional language using recursion. As long as you only use tail-recursion, it will be just as efficient as a while loop in your favorite imperative language.
Related
I have a program that is trying to take in a list of ints and return a int list that has all the odd numbers from it, i'm new to functional programming and am trying to learn it with F#. When I try and call the removeEvens in main it gives me this error
Error FS0001 This expression was expected to have type
'int list -> 'a'
but here has type
''b list'
and here is my code
open System
let rec removeEvens arr count ret =
if count < 0 then
ret
else
if count % 2 = 0 then
removeEvens arr (count + 1) ret
else
removeEvens arr (count + 1) (arr[count] :: ret)
let rec printResults arr count =
if count > 0 then
printfn "%d" (arr[count])
printResults arr (count + 1)
[<EntryPoint>]
let main argv =
printResults (removeEvens [0 .. 100] 0 []) 0
0
Syntactically, the only problem here is that the index operator is missing a . character. So you want arr.[count] instead of arr[count] (which the F# compiler thinks is the application of a function called arr to a singleton list, hence the compiler error). In order to use indexing, you'll also need to explicitly annotate your arr value as a list, like this: (arr : List<_>).
Semantically, you should be aware that indexing into lists in this way is inefficient, but that's a separate issue. I suggest instead that a more elegant way to remove even numbers from a list is to consider only the head element of the list inside your recursive function.
I have the following question "Given a list of integer pairs, write a function to return a list of even numbers in that list in sml".
this is what I've achieved so far
val x = [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
fun isEven(num : int) =
if num mod 2 = 0 then num else 0;
fun evenNumbers(list : (int * int) list) =
if null list then [] else
if isEven(#1 (hd list)) <> 0
then if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
else []
else if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: evenNumbers(tl list)
else [];
evenNumbers(x);
the result should be like this [6,2,4,6,8,10]
any help would be appreciated.
I see two obvious problems.
If both the first and second number are even, you do
#1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
which adds the first number twice and ignores the second.
If the first number is odd and the second even, you do
#1 (hd list) :: evenNumbers(tl list)
which adds the number that you know is odd and ignores the one you know is even.
Programming with selectors and conditionals gets complicated very quickly (as you've noticed).
With pattern matching, you could write
fun evenNumbers [] = []
| evenNumber ((x,y)::xys) = ...
and reduce the risk of using the wrong selector.
However, this still makes for complicated logic, and there is a better way.
Consider the simpler problem of filtering the odd numbers out of a list of numbers, not pairs.
If you transform the input into such a list, you only need to solve that simpler problem (and there's a fair chance that you've already solved something very similar in a previous exercise).
Exercise: implement this transformation. Its type will be ('a * 'a) list -> 'a list.
Also, your isEven is more useful if it produces a truth value (if you ask someone, "is 36 even?", "36" is a very strange answer).
fun isEven x = x mod 2 = 0
Now, evenNumbers can be implemented as "just" a combination of other, more general, functions.
So running your current code,
- evenNumbers [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
val it = [6,6,3,5,7,9] : int list
suggests that you're not catching all even numbers, and that you're catching some odd numbers.
The function isEven sounds very much like you want to have the type int -> bool like so:
fun isEven n =
n mod 2 = 0
Instead of addressing the logic error of your current solution, I would like to propose a syntactically much simpler approach which is to use pattern matching and fewer explicit type annotations. One basis for such a solution could look like:
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) = ...
Using pattern matching is an alternative to if-then-else: the [] pattern is equivalent to if null list ... and the (x,y)::pairs pattern matches when the input list is non-empty (holds at least one element, being (x,y). At the same time, it deconstructs this one element into its parts, x and y. So in the second function body you can express isEven x and isEven y.
As there is a total of four combinations of whether x and y are even or not, this could easily end up with a similarly complicated nest of if-then-else's. For this I might do either one of two things:
Use case-of (and call evenNumbers recursively on pairs):
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) =
case (isEven x, isEven y) of
... => ...
| ... => ...
Flatten the list of pairs into a list of integers and filter it:
fun flatten [] = ...
| flatten ((x,y)::pairs) = ...
val evenNumbers pairs = ...
I am absolute OCaml beginner. I want to create a function that repeats characters 20 times.
This is the function, but it does not work because of an error.
let string20 s =
let n = 20 in
s ^ string20 s (n - 1);;
string20 "u";;
I want to run like this
# string20 "u"
- : string = "uuuuuuuuuuuuuuuuuuuu"
Your function string20 takes one parameter but you are calling it recursively with 2 parameters.
The basic ideas are in there, but not quite in the right form. One way to proceed is to separate out the 2-parameter function as a separate "helper" function. As #PierreG points out, you'll need to delcare the helper function as a recursive function.
let rec string n s =
if n = 0 then "" else s ^ string (n - 1) s
let string20 = string 20
It is a common pattern to separate a function into a "fixed" part and inductive part. In this case, a nested helper function is needed to do the real recursive work in a new scope while we want to fix an input string s as a constant so we can use to append to s2. s2 is an accumulator that build up the train of strings over time while c is an inductor counting down to 1 toward the base case.
let repeat s n =
let rec helper s1 n1 =
if n1 = 0 then s1 else helper (s1 ^ s) (n1 - 1)
in helper "" n
A non-tail call versions is more straightforward since you won't need a helper function at all:
let rec repeat s n =
if n = 0 then "" else s ^ repeat s (n - 1)
On the side note, one very fun thing about a functional language with first-class functions like Ocaml is currying (or partial application). In this case you can create a function named repeat that takes two arguments n of type int and s of type string as above and partially apply it to either n or s like this:
# (* top-level *)
# let repeat_foo = repeat "foo";;
# repeat_foo 5;;
- : bytes = "foofoofoofoofoo" (* top-level output *)
if the n argument was labeled as below:
let rec repeat ?(n = 0) s =
if n = 0 then "" else s ^ repeat s (n - 1)
The order of application can be exploited, making the function more flexible:
# (* top-level *)
# let repeat_10 = repeat ~n:10;;
# repeat_10 "foo";;
- : bytes = "foofoofoofoofoofoofoofoofoofoo" (* top-level output *)
See my post Currying Exercise in JavaScript (though it is in JavaScript but pretty simple to follow) and this lambda calculus primer.
Recursive functions in Ocaml are defined with let rec
As pointed out in the comments you've defined your function to take one parameter but you're trying to recursively call with two.
You probably want something like this:
let rec stringn s n =
match n with
1 -> s
| _ -> s ^ stringn s (n - 1)
;;
I'm trying to write some code in a functional paradigm for practice. There is one case I'm having some problems wrapping my head around. I am trying to create an array of 5 unique integers from 1, 100. I have been able to solve this without using functional programming:
let uniqueArray = [];
while (uniqueArray.length< 5) {
const newNumber = getRandom1to100();
if (uniqueArray.indexOf(newNumber) < 0) {
uniqueArray.push(newNumber)
}
}
I have access to lodash so I can use that. I was thinking along the lines of:
const uniqueArray = [
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100(),
getRandom1to100()
].map((currentVal, index, array) => {
return array.indexOf(currentVal) > -1 ? getRandom1to100 : currentVal;
});
But this obviously wouldn't work because it will always return true because the index is going to be in the array (with more work I could remove that defect) but more importantly it doesn't check for a second time that all values are unique. However, I'm not quite sure how to functionaly mimic a while loop.
Here's an example in OCaml, the key point is that you use accumulators and recursion.
let make () =
Random.self_init ();
let rec make_list prev current max accum =
let number = Random.int 100 in
if current = max then accum
else begin
if number <> prev
then (number + prev) :: make_list number (current + 1) max accum
else accum
end
in
make_list 0 0 5 [] |> Array.of_list
This won't guarantee that the array will be unique, since its only checking by the previous. You could fix that by hiding a hashtable in the closure between make and make_list and doing a constant time lookup.
Here is a stream-based Python approach.
Python's version of a lazy stream is a generator. They can be produced in various ways, including by something which looks like a function definition but uses the key word yield rather than return. For example:
import random
def randNums(a,b):
while True:
yield random.randint(a,b)
Normally generators are used in for-loops but this last generator has an infinite loop hence would hang if you try to iterate over it. Instead, you can use the built-in function next() to get the next item in the string. It is convenient to write a function which works something like Haskell's take:
def take(n,stream):
items = []
for i in range(n):
try:
items.append(next(stream))
except StopIteration:
return items
return items
In Python StopIteration is raised when a generator is exhausted. If this happens before n items, this code just returns however much has been generated, so perhaps I should call it takeAtMost. If you ditch the error-handling then it will crash if there are not enough items -- which maybe you want. In any event, this is used like:
>>> s = randNums(1,10)
>>> take(5,s)
[6, 6, 8, 7, 2]
of course, this allows for repeats.
To make things unique (and to do so in a functional way) we can write a function which takes a stream as input and returns a stream consisting of unique items as output:
def unique(stream):
def f(s):
items = set()
while True:
try:
x = next(s)
if not x in items:
items.add(x)
yield x
except StopIteration:
raise StopIteration
return f(stream)
this creates an stream in a closure that contains a set which can keep track of items that have been seen, only yielding items which are unique. Here I am passing on any StopIteration exception. If the underlying generator has no more elements then there are no more unique elements. I am not 100% sure if I need to explicitly pass on the exception -- (it might happen automatically) but it seems clean to do so.
Used like this:
>>> take(5,unique(randNums(1,10)))
[7, 2, 5, 1, 6]
take(10,unique(randNums(1,10))) will yield a random permutation of 1-10. take(11,unique(randNums(1,10))) will never terminate.
This is a very good question. It's actually quite common. It's even sometimes asked as an interview question.
Here's my solution to generating 5 integers from 0 to 100.
let rec take lst n =
if n = 0 then []
else
match lst with
| [] -> []
| x :: xs -> x :: take xs (n-1)
let shuffle d =
let nd = List.map (fun c -> (Random.bits (), c)) d in
let sond = List.sort compare nd in
List.map snd sond
let rec range a b =
if a >= b then []
else a :: range (a+1) b;;
let _ =
print_endline
(String.concat "\t" ("5 random integers:" :: List.map string_of_int (take (shuffle (range 0 101)) 5)))
How's this:
const addUnique = (ar) => {
const el = getRandom1to100();
return ar.includes(el) ? ar : ar.concat([el])
}
const uniqueArray = (numberOfElements, baseArray) => {
if (numberOfElements < baseArray.length) throw 'invalid input'
return baseArray.length === numberOfElements ? baseArray : uniqueArray(numberOfElements, addUnique(baseArray))
}
const myArray = uniqueArray(5, [])
I wrote a recursive version of index as follows
let index list value =
let rec counter num = function
| [] -> -1
| h::t ->
if h == value
then num
else (counter (num + 1)) t
in counter 0 list;;
It works, but then our professor said we should use a tail recursive version in order to not timeout on the server, so I wrote a new index function using fold, but I can't seem to figure out why if it doesn't find the element, it returns a number greater than the length of the list, even though I want it to return -1.
let index2 list value = fold (fun i v ->
if i > (length list) then -1
else if v == value then i
else i+1) 0 list;;
Here's my fold version as well:
let rec fold f a l = match l with
[] -> a
| (h::t) -> fold f (f a h) t;;
Your folded function is called once for each element of the list. So you'll never see a value of i that's greater than (length list - 1).
As a side comment, it's quite inefficient (quadratic complexity) to keep calculating the length of the list. It would be better to calculate it once at the beginning.
As another side comment, you almost never want to use the == operator. Use the = operator instead.
EDIT
Why do you redefine fold instead of using List.fold_left?
Your first version of index is already tail recursive, but you can improve its style by:
using option type instead of returning -1 if not found;
directly call index recursively instead of a count function;
use = (structural) comparator instead of == (physical);
use a guard in your pattern matching instead of an if statement.
So
let index list value =
let rec index' list value i = match list with
| [] -> None
| h :: _ when h = value -> Some i
| _ :: t -> index' t value (succ i)
in index' list value 0
And as already said, index2 does not work because you'll never reach an element whose index is greater than the length of the list, so you just have to replace i > (length list) with i = (length list) - 1 to make it work.
But index2 is less efficient than index because index stops as soon as the element is found whereas index2 always evaluate each element of the list and compare the list length to the counter each time.