Sublists of N length function in Erlang style - functional-programming

I've been learning Erlang and tried completing some practise functions. I struggled making one function in particular and think it might be due to me not thinking "Erlang" enough.
The function in question takes a list and a sublist size then produces a list of tuples containing the number of elements before the a sublist, the sublist itself and the number of elements after the sublist. For example
sublists(1,[a,b,c])=:=[{0,[a],2}, {1,[b],1}, {2,[c],0}].
sublists(2,[a,b,c])=:=[{0,[a,b],1}, {1,[b,c],0}].
My working solution was
sublists(SubListSize, [H | T]) ->
Length = length(1, T),
sublists(SubListSize, Length, Length-SubListSize, [H|T], []).
sublists(_, _, -1, _, Acc) -> lists:reverse(Acc);
sublists(SubSize, Length, Count, [H|T], Acc) ->
Sub = {Length-SubSize-Count, grab(SubSize, [H|T],[]),Count},
sublists(SubSize, Length, Count-1, T, [Sub|Acc]).
length(N, []) -> N;
length(N, [_|T]) -> length(N+1, T).
grab(0, _, Acc) -> lists:reverse(Acc);
grab(N, [H|T], Acc) -> grab(N-1, T, [H|Acc]).
but it doesn't feel right and I wondered if there was a better way?
There was an extension that asked for the sublists function to be re-implemented using a list comprehension. My failed attempt was
sublist_lc(SubSize, L) ->
Length = length(0, L),
Indexed = lists:zip(L, lists:seq(0, Length-1)),
[{I, X, Length-1-SubSize} || {X,I} <- Indexed, I =< Length-SubSize].
As I understand it, list comprehensions can't see ahead so I was unable to use my grab function from earlier. This again makes me thing there must be a better way of solving this problem.

I show a few approaches below. All protect against the case where the requested sublist length is greater than the list length. All use functions from the standard lists module.
The first one uses lists:split/2 to capture each sublist and the length of the remaining tail list, and uses a counter C to keep track of how many elements precede the sublist. The length of the remaining tail list, named Rest, gives the number of elements that follow each sublist.
sublists(N,L) when N =< length(L) ->
sublists(N,L,[],0).
sublists(N,L,Acc,C) when N == length(L) ->
lists:reverse([{C,L,0}|Acc]);
sublists(N,[_|T]=L,Acc,C) ->
{SL,Rest} = lists:split(N,L),
sublists(N,T,[{C,SL,length(Rest)}|Acc],C+1).
The next one uses two lists of counters, one indicating how many elements precede the sublist and the other indicating how many follow it. The first is easily calculated by simply counting from 0 to the length of the input list minus the length of each sublist, and the second list of counters is just the reverse of the first. These counter lists are also used to control recursion; we stop when each contains only a single element, indicating we've reached the final sublist and can end the recursion. This approach uses the lists:sublist/2 call to obtain all but the final sublist.
sublists(N,L) when N =< length(L) ->
Up = lists:seq(0,length(L)-N),
Down = lists:reverse(Up),
sublists(N,L,[],{Up,Down}).
sublists(_,L,Acc,{[U],[D]}) ->
lists:reverse([{U,L,D}|Acc]);
sublists(N,[_|T]=L,Acc,{[U|UT],[D|DT]}) ->
sublists(N,T,[{U,lists:sublist(L,N),D}|Acc],{UT,DT}).
And finally, here's a solution based on a list comprehension. It's similar to the previous solution in that it uses two lists of counters to control iteration. It also makes use of lists:nthtail/2 and lists:sublist/2 to obtain each sublist, which admittedly isn't very efficient; no doubt it can be improved.
sublists(N,L) when N =< length(L) ->
Up = lists:seq(0,length(L)-N),
Down = lists:reverse(Up),
[{U,lists:sublist(lists:nthtail(U,L),N),D} || {U,D} <- lists:zip(Up,Down)].
Oh, and a word of caution: your code implements a function named length/2, which is somewhat confusing because it has the same name as the standard length/1 function. I recommend avoiding naming your functions the same as such commonly-used standard functions.

Related

SMLNJ powerset function

I am trying to print the size of a list created from below power set function
fun add x ys = x :: ys;
fun powerset ([]) = [[]]
| powerset (x::xr) = powerset xr # map (add x) (powerset xr) ;
val it = [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]] : int list list;
I have the list size function
fun size xs = (foldr op+ 0 o map (fn x => 1)) xs;
I couldnt able to merge these two functions and get the result like
I need something like this:
[(0,[]),(1,[3]),(1,[2]),(2,[2,3]),(1,[1]),(2,[1,3]),(2,[1,2]),(3,[1,2,3])]
Could anyone please help me with this?
You can get the length of a list using the built-in List.length.
You seem to forget to mention that you have the constraint that you can only use higher-order functions. (I am guessing you have this constraint because others these days are asking how to write powerset functions with this constraint, and using foldr to count, like you do, seems a little constructed.)
Your example indicates that you are trying to count each list in a list of lists, and not just the length of one list. For that you'd want to map the counting function across your list of lists. But that'd just give you a list of lengths, and your desired output seems to be a list of tuples containing both the length and the actual list.
Here are some hints:
You might as well use foldl rather than foldr since addition is associative.
You don't need to first map (fn x => 1) - this adds an unnecessary iteration of the list. You're probably doing this because folding seems complicated and you only just managed to write foldr op+ 0. This is symptomatic of not having understood the first argument of fold.
Try, instead of op+, to write the fold expression using an anonymous function:
fun size L = foldl (fn (x, acc) => ...) 0 L
Compare this to op+ which, if written like an anonymous function, would look like:
fn (x, y) => x + y
Folding with op+ carries some very implicit uses of the + operator: You want to discard one operand (since not its value but its presence counts) and use the other one as an accumulating variable (which is better understood by calling it acc rather than y).
If you're unsure what I mean about accumulating variable, consider this recursive version of size:
fun size L =
let fun sizeHelper ([], acc) = acc
| sizeHelper (x::xs, acc) = sizeHelper (xs, 1+acc)
in sizeHelper (L, 0) end
Its helper function has an extra argument for carrying a result through recursive calls. This makes the function tail-recursive, and folding is one generalisation of this technique; the second argument to fold's helper function (given as an argument) is the accumulating variable. (The first argument to fold's helper function is a single argument rather than a list, unlike the explicitly recursive version of size above.)
Given your size function (aka List.length), you're only a third of the way, since
size [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]
gives you 8 and not [(0,[]),(1,[3]),(1,[2]),(2,[2,3]),...)]
So you need to write another function that (a) applies size to each element, which would give you [0,1,1,2,...], and (b) somehow combine that with the input list [[],[3],[2],[2,3],...]. You could do that either in two steps using zip/map, or in one step using only foldr.
Try and write a foldr expression that does nothing to an input list L:
foldr (fn (x, acc) => ...) [] L
(Like with op+, doing op:: instead of writing an anonymous function would be cheating.)
Then think of each x as a list.

How to make an tail recursive function and test it?

I would like to make this functions recursive but I don't know where to start.
let rec rlist r n =
if n < 1 then []
else Random.int r :: rlist r (n-1);;
let rec divide = function
h1::h2::t -> let t1,t2 = divide t in
h1::t1, h2::t2
| l -> l,[];;
let rec merge ord (l1,l2) = match l1,l2 with
[],l | l,[] -> l
| h1::t1,h2::t2 -> if ord h1 h2
then h1::merge ord (t1,l2)
else h2::merge ord (l1,t2);;
Is there any way to test if a function is recursive or not?
If you give a man a fish, you feed him for a day. But if you give him a fishing rod, you feed him for a lifetime.
Thus, instead of giving you the solution, I would better teach you how to solve it yourself.
A tail-recursive function is a recursive function, where all recursive calls are in a tail position. A call position is called a tail position if it is the last call in a function, i.e., if the result of a called function will become a result of a caller.
Let's take the following simple function as our working example:
let rec sum n = if n = 0 then 0 else n + sum (n-1)
It is not a tail-recursive function as the call sum (n-1) is not in a tail position because its result is then incremented by one. It is not always easy to translate a general recursive function into a tail-recursive form. Sometimes, there is a tradeoff between efficiency, readability, and tail-recursion.
The general techniques are:
use accumulator
use continuation-passing style
Using accumulator
Sometimes a function really needs to store the intermediate results, because the result of recursion must be combined in a non-trivial way. A recursive function gives us a free container to store arbitrary data - the call stack. A place, where the language runtime, stores parameters for the currently called functions. Unfortunately, the stack container is bounded, and its size is unpredictable. So, sometimes, it is better to switch from the stack to the heap. The latter is slightly slower (because it introduces more work to the garbage collector), but is bigger and more controllable. In our case, we need only one word to store the running sum, so we have a clear win. We are using less space, and we're not introducing any memory garbage:
let sum n =
let rec loop n acc = if n = 0 then acc else loop (n-1) (acc+n) in
loop n 0
However, as you may see, this came with a tradeoff - the implementation became slightly bigger and less understandable.
We used here a general pattern. Since we need to introduce an accumulator, we need an extra parameter. Since we don't want or can't change the interface of our function, we introduce a new helper function, that is recursive and will carry the extra parameter. The trick here is that we apply the summation before we do the recursive call, not after.
Using continuation-passing style
It is not always the case when you can rewrite your recursive algorithm using an accumulator. In this case, a more general technique can be used - the continuation-passing style. Basically, it is close to the previous technique, but we will use a continuation in the place of an accumulator. A continuation is a function, that will actually postpone the work, that is needed to be done after the recursion, to a later time. Conventionally, we call this function return or simply k (for the continuation). Mentally, the continuation is a way of throwing the result of computation back into the future. "Back" is because you returning the result back to the caller, in the future, because, the result will be used not now, but once everything is ready. But let's look at the implementation:
let sum n =
let rec loop n k = if n = 0 then k 0 else loop (n-1) (fun x -> k (x+n)) in
loop n (fun x -> x)
You may see, that we employed the same strategy, except that instead of int accumulator we used a function k as a second parameter. If the base case, if n is zero, we will return 0, (you can read k 0 as return 0). In the general case, we recurse in a tail position, with a regular decrement of the inductive variable n, however, we pack the work, that should be done with the result of the recursive function into a function: fun x -> k (x+n). Basically, this function says, once x - the result of recursion call is ready, add it to the number n and return. (Again, if we will use name return instead of k it could be more readable: fun x -> return (x+n)).
There is no magic here, we still have the same tradeoff, as with accumulator, as we create a new closure (functional object) at every recursive call. And each newly created closure contains a reference to the previous one (that was passed via the parameter). For example, fun x -> k (x+n) is a function, that captures two free variables, the value n and function k, that was the previous continuation. Basically, these continuations form a linked list, where each node bears a computation and all arguments except one. So, the computation is delayed until the last one is known.
Of course, for our simple example, there is no need to use CPS, since it will create unnecessary garbage and be much slower. This is only for demonstration. However, for more complex algorithms, in particular for those that combine results of two or more recursive calls in a non-trivial case, e.g., folding over a graph data structure.
So now, armed with the new knowledge, I hope that you will be able to solve your problems as easy as pie.
Testing for the tail recursion
The tail call is a pretty well-defined syntactic notion, so it should be pretty obvious whether the call is in a tail position or not. However, there are still few methods that allow one to check whether the call is in a tail position. In fact, there are other cases, when tail-call optimization may come into play. For example, a call that is right to the shortcircuit logical operator is also a tail call. So, it is not always obvious when a call is using the stack or it is a tail call. The new version of OCaml allows one to put an annotation at the call place, e.g.,
let rec sum n = if n = 0 then 0 else n + (sum [#tailcall]) (n-1)
If the call is not really a tail call, a warning is issued by a compiler:
Warning 51: expected tailcall
Another method is to compile with -annot option. The annotation file will contain an annotation for each call, for example, if we will put the above function into a file sum.ml and compile with ocamlc -annot sum.ml, then we can open sum.annot file and look for all calls:
"sum.ml" 1 0 41 "sum.ml" 1 0 64
call(
stack
)
If we, however, put our third implementation, then the see that all calls are tail calls, e.g. grep call -A1 sum.annot:
call(
tail
--
call(
tail
--
call(
tail
--
call(
tail
Finally, you can just test your program with some big input, and see whether your program will fail with the stack overflow. You can even reduce the size of the stack, this can be controlled with the environment variable OCAMLRUNPARAM, for example, to limit the stack to one thousand words:
export OCAMLRUNPARAM='l=1000'
ocaml sum.ml
You could do the following :
let rlist r n =
let aux acc n =
if n < 1 then acc
else aux (Random.int r :: acc) (n-1)
in aux [] n;;
let divide l =
let aux acc1 acc2 = function
| h1::h2::t ->
aux (h1::acc1) (h2::acc2) t
| [e] -> e::acc1, acc2
| [] -> acc1, acc2
in aux [] [] l;;
But for divide I prefer this solution :
let divide l =
let aux acc1 acc2 = function
| [] -> acc1, acc2
| hd::tl -> aux acc2 (hd :: acc1) tl
in aux [] [] l;;
let merge ord (l1,l2) =
let rec aux acc l1 l2 =
match l1,l2 with
| [],l | l,[] -> List.rev_append acc l
| h1::t1,h2::t2 -> if ord h1 h2
then aux (h1 :: acc) t1 l2
else aux (h2 :: acc) l1 t2
in aux [] l1 l2;;
As to your question about testing if a function is tail recursive or not, by looking out for it a bit you would have find it here.

New to SML / NJ. Making a custom insert function

Define a function that, given a list L, an object x, and a positive
integer k, returns a copy of L with x inserted at the k-th position.
For example, if L is [a1, a2, a3] and k=2, then [a1, x, a2, a3] is
returned. If the length of L is less than k, insert at the end. For
this kind of problems, you are supposed not to use, for example, the
length function. Think about how the function computes the length. No
'if-then-else' or any auxiliary function.
I've figured out how to make a function to find the length of a list
fun mylength ([]) = 0
| mylength (x::xs) = 1+ mylength(xs)
But, as the questions states, I can't use this as an auxiliary function in the insert function. Also, i'm lost as to how to go about the insert function? Any help or guidance would be appreciated!
Here's how to do this. Each recursive call you pass to the function tail of the list and (k - 1) - position of the new element in the tail of the list. When the list is empty, you construct a single-element list (which was given to you); when k is 0, you append your element to what's left from the list. On the way back, you append all heads of the list that you unwrapped before.
fun kinsert [] x k = [x]
| kinsert ls x 0 = x::ls
| kinsert (l::ls) x k = l::(kinsert ls x (k - 1))
I used a 0-indexed list; if you want 1-indexed, just replace 0 with 1.
As you can see, it's almost the same as your mylength function. The difference is that there are two base cases for recursion and your operation on the way back is not +, but ::.
Edit
You can call it like this
kinsert [1,2,3,4,5,6] 10 3;
It has 3 arguments; unlike your length function, it does not wrap arguments in a tuple.
Here's how I'd approach it. The following assumes that the list item starts from zero.
fun mylength (lst,obj,pos) =
case (lst,obj,pos) of
([],ob,po)=>[ob]
| (xs::ys,ob,0) => ob::lst
| (xs::ys,ob,po) => xs::mylength(ys,obj,pos-1)

Beginner to SML / NJ. How to find largest Value in list

We want to find the largest value in a given nonempty list of integers. Then we have to compare elements in the list. Since data
values are given as a sequence, we can do comparisons from the
beginning or from the end of the list. Define in both ways. a)
comparison from the beginning b) comparison from the end (How can we
do this when data values are in a list?) No auxiliary functions.
I've been playing around a lot with recursive functions, but can't seem to figure out how to compare two values in the list.
fun listCompare [] = 0
| listCompare [x] = x
| listCompare (x::xs) = listCompare(xs)
This will break the list down to the last element, but how do I start comparing and composing the list back up?
You could compare the first two elements of a given list and keep the larger element in the list and drop the other. Once the list has only one element, then you have the maximum. In functional pseudocode for a) it looks roughly like so:
lmax [] = error "empty list"
lmax [x] = x
lmax (x::y::xs) =
if x > y then lmax (x::xs)
else lmax (y::xs)
For b) you could reverse the list first.
This is what the foldl (or foldr) function in the SML list library is for :
foldl : ((`a * `b) -> `b) -> `b -> `a list -> `b
You can simply add an anonymous function to compare the current element against the accumulator :
fun lMax l =
foldl (fn (x,y) => if x > y then x else y) (nth l 0) l
The nth function simply takes the int list : l and an int : 0 to return the first element in the list. As lists in SML are written recursively as : h :: t, retrieving the first element is an O(1) operation, and using the foldl function greatly increases the elegance of code. The whole point of having a functional language is to define abstractions to pass around anonymous functions as higher-order functions and re-use the abstract type definitions with concrete functions.

Keeping a counter at each recursive call in OCaml

I am trying to write a function that returns the index of the passed value v in a given list x; -1 if not found. My attempt at the solution:
let rec index (x, v) =
let i = 0 in
match x with
[] -> -1
| (curr::rest) -> if(curr == v) then
i
else
succ i; (* i++ *)
index(rest, v)
;;
This is obviously wrong to me (it will return -1 every time) because it redefines i at each pass. I have some obscure ways of doing it with separate functions in my head, none which I can write down at the moment. I know this is a common pattern in all programming, so my question is, what's the best way to do this in OCaml?
Mutation is not a common way to solve problems in OCaml. For this task, you should use recursion and accumulate results by changing the index i on certain conditions:
let index(x, v) =
let rec loop x i =
match x with
| [] -> -1
| h::t when h = v -> i
| _::t -> loop t (i+1)
in loop x 0
Another thing is that using -1 as an exceptional case is not a good idea. You may forget this assumption somewhere and treat it as other indices. In OCaml, it's better to treat this exception using option type so the compiler forces you to take care of None every time:
let index(x, v) =
let rec loop x i =
match x with
| [] -> None
| h::t when h = v -> Some i
| _::t -> loop t (i+1)
in loop x 0
This is pretty clearly a homework problem, so I'll just make two comments.
First, values like i are immutable in OCaml. Their values don't change. So succ i doesn't do what your comment says. It doesn't change the value of i. It just returns a value that's one bigger than i. It's equivalent to i + 1, not to i++.
Second the essence of recursion is to imagine how you would solve the problem if you already had a function that solves the problem! The only trick is that you're only allowed to pass this other function a smaller version of the problem. In your case, a smaller version of the problem is one where the list is shorter.
You can't mutate variables in OCaml (well, there is a way but you really shouldn't for simple things like this)
A basic trick you can do is create a helper function that receives extra arguments corresponding to the variables you want to "mutate". Note how I added an extra parameter for the i and also "mutate" the current list head in a similar way.
let rec index_helper (x, vs, i) =
match vs with
[] -> -1
| (curr::rest) ->
if(curr == x) then
i
else
index_helper (x, rest, i+1)
;;
let index (x, vs) = index_helper (x, vs, 0) ;;
This kind of tail-recursive transformation is a way to translate loops to functional programming but to be honest it is kind of low level (you have full power but the manual recursion looks like programming with gotos...).
For some particular patterns what you can instead try to do is take advantage of reusable higher order functions, such as map or folds.

Resources