OCaml swapping elements in a list - ocaml

I'm trying to swap two elements in a list, not really sure why mines not working.
The correct implementation should do the following:
list_swap_val [5;6;7;3] 75 => [7;6;5;3]
list_swap_val [5;6;3] 7 5 => [7;6;3]
Here's two different implementations I've tried but both seem to just return the original list
let rec list_swap l u v =
match l with
|[] -> []
|h::t -> if h = u then u::(list_swap t u v)
else if h = v then v::(list_swap t u v)
else h::(list_swap t u v) ;;
I also tried to do the above but with while in the match statements instead of using if, but both are not working. Where am I going wrong? Thanks for any help

You forgot to actually swap values: when you see a u, the first element of your returned list should be v. Here, it is as-if you build h::(list_swap t u v) in all cases.
By the way, you can factorize the recursive call, which gives you finally this definition:
let rec list_swap l u v =
match l with
| [] -> []
| h::t -> (if h = u then v
else if h = v then u
else h)::(list_swap t u v);;

As coredump- wrote you can factorize it, but you can go even further and notice that this is a map.
let swap u v x = if x = u then v else if x = v then u else x
let list_swap u v = List.map (swap u v)

as said above, you forgot to swap. You can also use List.map :
let swap u v n = match n with
|x when x = u -> v
|x when x = v -> u
|_ -> n;;
let list_swap l u v = List.map (swap u v) l;;
This calls the function "swap u v" (thanks to partial evaluation) on every element in the list "l".
However, this hides the recursive call and you should know map isn't tail-recursive. If you want to use map and have tail recursivity :
let list_swap l u v = List.rev (List.rev_map swap (u v) l);;
"rev_map" is the same as "map" except it reverses the list at the same time, and it is tail recursive. So you reverse the list once again afterwards. "rev" is also tail recursive !

Related

replace all the n occurences in a list per a given list - ocaml

example remplace_par_liste 2 [-4;-5] [1;2;3;2;2;9] --> [1;-4;-5;3;-4;-5-4;-5;9]
I know how to do it with an occurence but not with a list.
example remplace 2 0 [1;2;3;2;2;9] --> [1; 0; 3; 0; 0; 9]
let listere = [1;2;3;2;2;9];;
let rec remplace n p liste = match liste with
[] -> []
|a::q -> (if a = n then p else a)::(remplace n p q);;
remplace 2 0 listere;;
- : int list = [1; 0; 3; 0; 0; 9]
And there is the problem, i need another funtion to insert the list l1 in the list ?
let listerel = [1;2;3;2;2;9];;
let l1 = [-4;-5];;
let rec remplace_par_liste n l1 liste = match liste with
[] -> []
(|a::q -> (if a = n then l1 else a)::(remplace_par_liste n l1 q);;)
remplace_par_liste 2 l1 listerel;;
File "", line 4, characters 113-114:
Error: This expression has type int list
but an expression was expected of type int```
I would suggest you define the second function first.
:: will let us add x to the front of the list created by recursively running the function on the tail of the list.
# will let us concatenate two lists so we can insert the values in the substitute list into the result.
let rec replace_value_with_list v sub lst =
match lst with
| [] -> []
| x::xs when x <> v -> x :: replace_value_with_list v sub xs
| x::xs -> sub # replace_value_with_list v sub xs
The first function is then much simpler, being just a specialized application of the second, putting that single value into a list.
let replace_value v sub lst =
replace_value_with_list v [sub] lst
Downsides to this implementation
I have decided to edit to mention this based on the comments. The above is not tail-recursive. Each time a function is called, it takes up a certain amount of stack space. The stack is limited. Recursively call a function or functions too many times and you will get a stack overflow error.
OCaml (and some other programming languages, primarily in the functional vein) offer tail-call optimization. If the compiler can determine that the last thing a function does is call itself or another function, then the space the caller occupies on the stack can be reused.
We can modify the existing function from ealier.
let rec replace_value_with_list v sub lst =
match lst with
| [] -> []
| x::xs when x <> v -> x :: replace_value_with_list v sub xs
| x::xs -> sub # replace_value_with_list v sub xs
This operation, for instance, makes the function non-tail-recursive:
x :: replace_value_with_list v sub xs
First we have to call replace_value_with_list v sub xs and then add x to the front of it. We can solve this issue by passing along an accumulator that builds up the list. We can hide this detail by using a local auxiliary function. Because the local function is taking care of the recursion, replace_value_with_list no longer needs to be marked as recursive.
let replace_value_with_list v sub lst =
let rec aux v sub lst acc =
match lst with
| [] -> List.rev acc
| x::xs when x <> v -> aux v sub xs (x :: acc)
| x::xs -> replace_value_with_list v sub xs (sub # acc)
in
aux v sub lst []
Note that when we call the aux function, it will build up the accumulator in the reverse order to the way we expect, so we need to reverse the accumulator on the exit condition.
However, this is still not optimal because the # operator which performs the concatenation is not tail-recursive. We can overcome this by replacing # with List.rev_append which is tail-recursive.
let replace_value_with_list v sub lst =
let rec aux v sub lst acc =
match lst with
| [] -> List.rev acc
| x::xs when x <> v -> aux v sub xs (x::acc)
| x::xs -> aux v sub xs (List.rev_append sub acc)
in
aux v sub lst []
This process of iterating over a list and accumulating a value is where folds really shine.
let rvl v sub lst =
List.(
let f acc x = if x <> v then x::acc else rev_append sub acc in
fold_left f [] lst |> rev
)

Implementing Haskell's `take` function using `foldl`

Implementing Haskell's take and drop functions using foldl.
Any suggestions on how to implement take and drop functions using foldl ??
take x ls = foldl ???
drop x ls = foldl ???
i've tried these but it's showing errors:
myFunc :: Int -> [a] -> [a]
myFunc n list = foldl func [] list
where
func x y | (length y) > n = x : y
| otherwise = y
ERROR PRODUCED :
*** Expression : foldl func [] list
*** Term : func
*** Type : a -> [a] -> [a]
*** Does not match : [a] -> [a] -> [a]
*** Because : unification would give infinite type
Can't be done.
Left fold necessarily diverges on infinite lists, but take n does not. This is so because left fold is tail recursive, so it must scan through the whole input list before it can start the processing.
With the right fold, it's
ntake :: Int -> [a] -> [a]
ntake 0 _ = []
ntake n xs = foldr g z xs 0
where
g x r i | i>=n = []
| otherwise = x : r (i+1)
z _ = []
ndrop :: Int -> [a] -> [a]
ndrop 0 xs = xs
ndrop n xs = foldr g z xs 0 xs
where
g x r i xs#(_:t) | i>=n = xs
| otherwise = r (i+1) t
z _ _ = []
ndrop implements a paramorphism nicely and faithfully, up to the order of arguments to the reducer function g, giving it access to both the current element x and the current list node xs (such that xs == (x:t)) as well as the recursive result r. A catamorphism's reducer has access only to x and r.
Folds usually encode catamorphisms, but this shows that right fold can be used to code up a paramorphism just as well. It's universal that way. I think it is beautiful.
As for the type error, to fix it just switch the arguments to your func:
func y x | ..... = .......
The accumulator in the left fold comes as the first argument to the reducer function.
If you really want it done with the left fold, and if you're really sure the lists are finite, two options:
ltake n xs = post $ foldl' g (0,id) xs
where
g (i,f) x | i < n = (i+1, f . (x:))
| otherwise = (i,f)
post (_,f) = f []
rltake n xs = foldl' g id xs r n
where
g acc x = acc . f x
f x r i | i > 0 = x : r (i-1)
| otherwise = []
r _ = []
The first counts from the left straight up, potentially stopping assembling the prefix in the middle of the full list traversal that it does carry to the end nevertheless, being a left fold.
The second also traverses the list in full turning it into a right fold which then gets to work counting down from the left again, being able to actually stop working as soon as the prefix is assembled.
Implementing drop this way is bound to be (?) even clunkier. Could be a nice exercise.
I note that you never specified the fold had to be over the supplied list. So, one approach that meets the letter of your question, though probably not the spirit, is:
sillytake :: Int -> [a] -> [a]
sillytake n xs = foldl go (const []) [1..n] xs
where go f _ (x:xs) = x : f xs
go _ _ [] = []
sillydrop :: Int -> [a] -> [a]
sillydrop n xs = foldl go id [1..n] xs
where go f _ (_:xs) = f xs
go _ _ [] = []
These each use left folds, but over the list of numbers [1..n] -- the numbers themselves are ignored, and the list is just used for its length to build a custom take n or drop n function for the given n. This function is then applied to the original supplied list xs.
These versions work fine on infinite lists:
> sillytake 5 $ sillydrop 5 $ [1..]
[6,7,8,9,10]
Will Ness showed a nice way to implement take with foldr. The least repulsive way to implement drop with foldr is this:
drop n0 xs0 = foldr go stop xs0 n0
where
stop _ = []
go x r n
| n <= 0 = x : r 0
| otherwise = r (n - 1)
Take the efficiency loss and rebuild the whole list if you have no choice! Better to drive a nail in with a screwdriver than drive a screw in with a hammer.
Both ways are horrible. But this one helps you understand how folds can be used to structure functions and what their limits are.
Folds just aren't the right tools for implementing drop; a paramorphism is the right tool.
You are not too far. Here are a pair of fixes.
First, note that func is passed the accumulator first (i.e. a list of a, in your case) and then the list element (an a). So, you need to swap the order of the arguments of func.
Then, if we want to mimic take, we need to add x when the length y is less than n, not greater!
So we get
myFunc :: Int -> [a] -> [a]
myFunc n list = foldl func [] list
where
func y x | (length y) < n = x : y
| otherwise = y
Test:
> myFunc 5 [1..10]
[5,4,3,2,1]
As you can see, this is reversing the string. This is because we add x at the front (x:y) instead of at the back (y++[x]). Or, alternatively, one could use reverse (foldl ....) to fix the order at the end.
Also, since foldl always scans the whole input list, myFunc 3 [1..1000000000] will take a lot of time, and myFunc 3 [1..] will fail to terminate. Using foldr would be much better.
drop is more tricky to do. I don't think you can easily do that without some post-processing like myFunc n xs = fst (foldl ...) or making foldl return a function which you immediately call (which is also a kind of post-processing).

Ocaml nested functions

Can someone explain the syntax used for when you have nested functions?
For example I have a outer and an inner recursive function.
let rec func1 list = match list with
[] -> []
|(head::tail) ->
let rec func2 list2 = match list2 with
...
;;
I have spent all day trying to figure this out and I'm getting a ever tiring "Syntax error".
You don't show enough code for the error to be obvious.
Here is a working example:
# let f x =
let g y = y * 5 in
g (x + 1);;
val f : int -> int = <fun>
# f 14;;
- : int = 75
Update
Something that might help until you're used to OCaml syntax is to use lots of extra parentheses:
let rec f y x =
match x with
| h :: t -> (
let incr v = if h = y then 1 + v else v in
incr (f y t)
)
| _ -> (
0
)
It's particularly hard to nest one match inside another without doing this sort of thing. This may be your actual problem rather than nested functions.

Function with unknown value works. OCaml

I cant understand some things in my code. It is program in OCaml which generates all distinct pairs from elements in list. Here's my code:
let rec tmp f list x =
match list with
| [] -> x
| h :: t -> f h (tmp f t x);;
(* ^ ^ (^ ) (1) *)
let rec distinctpairs lst =
match lst with
| [] -> []
| h :: t -> tmp ( fun x lt -> (h,x)::lt) t (distinctpairs t);;
(* ^ ^ (2) *)
Do function tmp returns three values ?
How i can give an argument to func, when i dont know what is x?
When i assume that tmp return three values, that why when I giving as arg to tmp the ( fun x lt -> (h,x)::lt) argument, and it works?
1. Do function tmp returns three values ?
let rec tmp f list x =
match list with
| [] -> x
| h :: t -> f h (tmp f t x);;
The simple answer to this question is no.
f h (tmp f t x) is not three value, instead, it is a function execution/application on f.
2. How i can give an argument to func, when i dont know what is x?
let rec distinctpairs lst =
match lst with
| [] -> []
| h :: t -> tmp ( fun x lt -> (h,x)::lt) t (distinctpairs t);;
The truth here is you know x. x is defined as a parameter of the anonymous function fun x lt -> (h, x)::lt.
When i assume that tmp return three values, that why when I giving as arg to tmp the ( fun x lt -> (h,x)::lt) argument, and it works?
First of all, when ocaml sees tmp f list x, ocaml does not know anything but tmp accepts 3 parameters.
When ocaml reaches | [] -> x, it knows whatever type x is, the tmp will return the same type as x.
When ocaml reaches | h::t -> f h (tmp f t x), it knows f must be a function and f will have 2 parameters: one with type of h and one with type of x
Then in your distinctpairs function, ( fun x lt -> (h,x)::lt) is an anonymous function which really matches the prediction above.
A better way to write the two functions:
let rec tmp f x = function
| [] -> []
| h :: t -> f h (tmp f x t)
let rec distinctpairs = function
| [] -> []
| h :: t -> tmp (fun x lt -> (h,x)::lt) (distinctpairs t) t
I also suggest you to read Real World Ocaml book. It is the newest and most comprehensive book on OCaml and it is good.
When you try to enter functional programming world, there is no shortcut. It is not like you learn Spanish as an English speaker. It is more like learning Chinese/Japanese as an English speaker.
The whole idea is quite different from Java or C# or C, and of course, much better than Java (my personal feeling). So I suggest you to learn from ground.

Haskell Function that Takes A Pair of Values and a List

My homework has been driving me up the wall. I am supposed to write a function called myRepl that takes a pair of values and a list and returns a new list such that each occurrence of the first value of the pair in the list is replaced with the second value.
Example:
ghci> myRepl (2,8) [1,2,3,4]
> [1,8,3,4].
So far I have something like this (but its very rough and not working well at all. I need help with the algorithm:
myRep1 (x,y) (z:zs) =
if null zs then []
else (if x == z then y : myRep1 zs
else myRep1 zs )
I don't know how to create a function that takes a pair of values and a list. I'm not sure what the proper syntax is for that, and I'm not sure how to go about the algorithm.
Any help would be appreciated.
How about something like:
repl (x,y) xs = map (\i -> if i==x then y else i) xs
Explanation
map is a function that takes a function, applies it to each value in the list, and combines all the return values of that function into a new list.
The \i -> notation is a shortcut for writing the full function definition:
-- Look at value i - if it's the same as x, replace it with y, else do nothing
replacerFunc x y i = if x == y then y else i
then we can rewrite the repl function:
repl (x, y) xs = map (replacerFunc x y) xs
I'm afraid the map function you just have to know - it is relatively easy to see how it works. See the docs:
http://www.haskell.org/hoogle/?hoogle=map
How to write this without map? Now, a good rule of thumb is to get the base case of the recursion out of the way first:
myRep1 _ [] = ???
Now you need a special case if the list element is the one you want to replace. I would recommend a guard for this, as it reads much better than if:
myRep1 (x,y) (z:zs)
| x == z = ???
| otherwise = ???
As this is home work, I left a few blanks for you to fill in :-)
myRepl :: Eq a => (a, a) -> [a] -> [a]
myRepl _ [] = []
myRepl (v, r) (x : xs) | x == v = r : myRepl (v, r) xs
| otherwise = x : myRepl (v, r) xs
Untupled arguments, pointfree, in terms of map:
replaceOccs :: Eq a => a -> a -> [a] -> [a]
replaceOccs v r = map (\ x -> if x == v then r else x)