Position of anonymous function’s parameters in SML’s foldl - sml

I need to write a function that takes a list of strings and finds the largest string in the list. In case of tie, it should return string closest to the end of the list. The catch is it needs to iterate through the list using List.foldl and cannot use recursive calls except for those in the library function of List,foldl.
The following code works fine.
fun longest_string2 str_list =
List.foldl(fn (x, acc) => if String.size x >= String.size acc then x else acc) "” str_list
If I run longest_string2 ["Apple", "ball", "Bpple”]; in REPL, I get val it = "Bpple" : string
However, if I reverse the arguments of anonymous function as below I get val it = "Apple" : string.
Since the anonymous function is accessing the elements by name and not position, why does this makes difference?

The definition of List.foldl is
fun foldl (f: 'a*'b->'b) (acc: 'b) (l: 'a list): 'b =
case l of
[] => acc
| x::xs => foldl f (f(x,acc)) xs
If you reverse arguments of the anonymous function, your function becomes the following: (correct me if I misinterpreted your question)
fun longest_string2 str_list =
List.foldl(fn (acc, x) => if String.size x >= String.size acc then x else acc) "” str_list
If your pass ["Apple", "ball", "Bpple”] as argument to longest_string2 now, the foldl function will pattern match your list with x::xs, where x is “Apple” and xs is ["ball", "Bpple”]. When you compute the updated accumulator using f(x, acc), x and acc gets swapped. In other words, in your anonymous function (with reversed arguments), you would be assuming that the first argument would be ”” and the second argument would be Apple but the implementation of List.foldl will pass f(“Apple”, “”). In this case, your anonymous function will label “Apple” as “acc” and “” as “x”.

#3123 has most answered the question, but has not directly addressed this statement in the question.
Since the anonymous function is accessing the elements by name and not
position, why does this makes difference?
foldl takes a function which takes a tuple as its argument, which is positional.
We could define a fold function which takes a record as its argument instead if we really wanted to achieve this:
fun namedFold _ acc [] = acc
| namedFold f acc (x::xs) =
namedFold f (f {acc=acc, x=x}) xs;
And then call it as:
namedFold (fn { acc, x } => acc + x) 0 [1,2,3,4]
Or as:
namedFold (fn { x, acc } => acc + x) 0 [1,2,3,4]
And get the same result.
But then the type of namedFold is fn :({acc: 'a, x: 'b} -> 'a) -> 'a -> 'b list -> 'a and it becomes essentially impossible to easily pass existing functions to it. With foldl defined the way it is, we can easily rewrite that previous called to namedFold as:
foldl op+ 0 [1,2,3,4]
Because op+ has the same signature as the first argument to foldl.

Related

Ocaml Type error: This expression has type 'a * 'b but an expression was expected of type 'c list

I'm required to output a pair of lists and I'm not understanding why the pair I'm returning is not of the correct type.
let rec split l = match l with
| [] -> []
| [y] -> [y]
| x :: xs ->
let rec helper l1 acc = match l1 with
| [] -> []
| x :: xs ->
if ((List.length xs) = ((List.length l) / 2)) then
(xs, (x :: acc))
else helper xs (x :: acc)
in helper l []
(Please take the time to copy/paste and format your code on SO rather than providing a link to an image. It makes it much easier to help, and more useful in the future.)
The first case of the match in your helper function doesn't return a pair. All the cases of a match need to return the same type (of course).
Note that the cases of your outermost match are also of different types (if you assume that helper returns a pair).

How to make a tail recursive function

I am really confused on how to make a function "Tail recursive".
Here is my function, but I don't know whether it is already tail recursive or not.
I am trying to merge two lists in Haskell.
merge2 :: Ord a =>[a]->[a]->[a]
merge2 xs [] = xs
merge2 [] ys = ys
merge2 (x:xs)(y:ys) = if y < x then y: merge2 (x:xs) ys else x :merge2 xs (y:ys)
Your function isn't tail-recursive; it's guarded recursive. However, guarded recursion is what you should be using in Haskell if you want to be memory efficient.
For a call to be a tail call, its result must be the result of the entire function. This definition applies to both recursive and non-recursive calls.
For example, in the code
f x y z = (x ++ y) ++ z
the call (x ++ y) ++ z is a tail call because its result is the result of the entire function. The call x ++ y is not a tail call.
For an example of tail-recursion, consider foldl:
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl _ acc [] = acc
foldl f acc (x:xs) = foldl f (f acc x) xs
The recursive call foldl f (f acc x) xs is a tail-recursive call because its result is the result of the entire function. Thus it's a tail call, and it is recursive being a call of foldl to itself.
The recursive calls in your code
merge2 (x:xs) (y:ys) = if y < x then y : merge2 (x:xs) ys
else x : merge2 xs (y:ys)
are not tail-recursive because they do not give the result of the entire function. The result of the call to merge2 is used as a part of the whole returned value, a new list. The (:) constructor, not the recursive call, gives the result of the entire function. And in fact, being lazy, (:) _ _ returns right away, and the holes _ are filled only later, if and when needed. That's why guarded recursion is space efficient.
However, tail-recursion doesn't guarantee space efficiency in a lazy language.
With lazy evaluation, Haskell builds up thunks, or structures in memory that represent code that is yet to be evaluated. Consider the evaluation of the following code:
foldl f 0 (1:2:3:[])
=> foldl f (f 0 1) (2:3:[])
=> foldl f (f (f 0 1) 2) (3:[])
=> foldl f (f (f (f 0 1) 2) 3) []
=> f (f (f 0 1) 2) 3
You can think of lazy evaluation as happening "outside-in." When the recursive calls to foldl are evaluated, thunks are built-up in the accumulator. So, tail recursion with accumulators is not space efficient in a lazy language because of the delayed evaluation (unless the accumulator is forced right away, before the next tail-recursive call is made, thus preventing the thunks build-up and instead presenting the already-calculated value, in the end).
Rather than tail recursion, you should try to use guarded recursion, where the recursive call is hidden inside a lazy data constructor. With lazy evaluation, expressions are evaluated until they are in weak head normal form (WHNF). An expression is in WHNF when it is either:
A lazy data constructor applied to arguments (e.g. Just (1 + 1))
A partially applied function (e.g. const 2)
A lambda expression (e.g. \x -> x)
Consider map:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
map (+1) (1:2:3:[])
=> (+1) 1 : map (+1) (2:3:[])
The expression (+1) 1 : map (+1) (2:3:[]) is in WHNF because of the (:) data constructor, and therefore evaluation stops at this point. Your merge2 function also uses guarded recursion, so it too is space-efficient in a lazy language.
TL;DR: In a lazy language, tail-recursion can still take up memory if it builds up thunks in the accumulator, while guarded recursion does not build up thunks.
Helpful links:
https://wiki.haskell.org/Tail_recursion
https://wiki.haskell.org/Stack_overflow
https://wiki.haskell.org/Thunk
https://wiki.haskell.org/Weak_head_normal_form
Does Haskell have tail-recursive optimization?
What is Weak Head Normal Form?

SML/NJ return even integers from int list with foldr

I'm using SML recently and I'm trying to solve a problem.
I should create a function that accept an int list and return even int list,
I've already created it :
fun evens [] = [] |
evens [x] = [x] |
evens(x::xs) =
case x mod 2 of
0 => x::evens xs |
1 => evens xs;
which gives the correct result but I need to use foldr
this is what I came up with:
fun evens [] = [] |
evens(x::xs) =
case x mod 2 of
0 => foldr (op ::) evens xs [x] |
1 => evens xs;
but it is not working, I'm still confused with how to use foldr in this case.
any advice?
First of all, with foldr you should be looking for a 1-line definition rather than a recursive definition using patterns and cases. The point of foldr is that it incorporates a common recursion pattern -- you just need to use the pattern.
The type of foldr is
fn : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
In your case 'b is int list and 'a is int. The 'b between the arrows in the middle of foldr's type is the seed value. It typically corresponds to a basis value. When you are constructing lists this basis value is typically []. Thus -- you need to concentrate on the key question of what should be folded over the list. In other words -- what function of type ('a * 'b -> 'b) should you pass to foldr? In your case you need to pass a function of type
int * int list -> int list
this should be a function which, when given an int and an int list either tacks the int onto the list (if it is even) or leaves the list alone. You could define this function ahead of time, define it using let, or just use an anonymous function.
Under the assumption that this is homework, I don't want to give a complete answer, but here is a function which uses foldr to obtain the positive entries in a list:
fun positives xs =
foldr (fn (x,xs) => if x >= 0 then x::xs else xs) [] xs;
-
- positives [3,~2,4,5,0,~1,~1,5];
val it = [3,4,5,0,5] : int list

Understanding foldl in ML

I need to write a function that takes a list of strings and finds the largest string in the list. The catch is it needs to iterate through the list using List.foldl and cannot use recursive calls except for those in the library function of List,foldl.
I wrote
fun longest_string1(xs)=
case xs of
[] => ""
| x::xs' => List.foldl((fn (s,x) => if String.size s > String.size x then s else x) "" x,)
with my interpretation being as follows:
-take in xs, if xs is empty return an empty string
-otherwise for the first item of xs call List.foldl
-List.foldl passes in an anonymous function that checks the length of s, which should represent the accumulator against the head item of the list. -Set the initial accumulator to be the empty string and the initial compare value to be the head of the initial list passed in by the higher order function
However, it does not type check.
I think my issue is in the understanding of the List.foldl function itself and how exactly it reads in its parameters. Can someone please provide some clarification?
So, for the code you posted:
You don't need the case for the empty list. foldl will take care of that for you. Just pass xs to foldl instead of x.
foldl is curried, so you shouldn't have parentheses around the parameters.
Other than that, it actually looks correct. Anyway, if you're still not sure how foldl works, here's a really long and thorough explanation ;)
Okay, let's start with List.foldl.
val foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
So, there are three parameters. One is a function which we'll worry about later, the second is a value of the same type as the return type, and the last is the list.
So, let's take a simple example - say we have a list of ints, and we want to sum all the numbers. We could do this:
fun sum [] = 0
| sum (x::xs) = x + sum xs
Or, we can use foldl (I'll write foldl instead of List.foldl from now, because I'm lazy).
So, we know that the list is the third parameter. The second should be some sort of starting value, or accumulator, something that would make sense if the list was empty. For a sum, that would be 0.
The first parameter is a function, and this is the tricky part. The type is:
fn : 'a * 'b -> 'b
Okay, so 'a is also the type of the elements in the list, so it makes sense if this is an item from the list. 'b is the type of the starting value and the return value.
What actually happens is that foldl calls the function with the first element in the list, and the accumulator. It then calls itself with the result as the new accumulator, and the rest of the list. So if we do this:
foldl foo 0 [1,2,3]
It'll do
foo (1,0)
And then
foldl foo (foo (1,0)) [2,3]
And so on.
So for summing a list, we'll make the following function:
fn (x,acc) => x + acc
So we can do this:
fun sum xs = foldl (fn (x,acc) => x + acc) 0 xs
Or, even simpler
val sum = foldl op+ 0
(op+ does the same as the anonymous function I used earlier)
Let's walk through it with the list [1,2,3]
foldl op+ 0 [1,2,3]
foldl op+ (op+ (1,0)) [2,3] -> foldl op+ 1 [2,3]
foldl op+ (op+ (2,1)) [3] -> foldl op+ 3 [3]
foldl op+ (op+ (3,3)) [] -> foldl op+ 6 []
6

How to use List.filter?

I have this code to filter list of string that the first letter is capital:
fun f s = Char.isUpper(String.sub(s,0));
fun only_capitals (xs : string list) = List.filter(f , xs);
But when compile, I always receive error :
operator domain: 'Z -> bool
operand: (string -> bool) * string list
in expression:
List.filter (f,xs)
What does this error mean? How to fix it?
Type signature of List.filter is
val filter : ('a -> bool) -> 'a list -> 'a list
So you need to give List.filter two distinct arguments, not one argument which happens to be a tuple.
You need to change it to:
fun only_capitals (xs : string list) = List.filter f xs
filter takes 2 arguments, a function f ('a -> bool) and a list.
It's easy to confuse syntax of passing a tuple in ML with the sytax of functional application in other languages.
You could also define it as:
val only_capitals = List.filter f
Functions in ML can take only one argument. Description from here (see also notes and video there).
List.filter is so called curried function, so List.filter f xs is actually (List.filter f) xs where List.filter f is a function. We have to provide f (fn: a -> bool) as an argument to List.filter, not tuple (f, xs).
Here is a simple example. When we call is_sorted 1 we get a closure with x in its environment. When we call this closure with 2 we get true because 1 <= 2.
val is_sorted = fn x => (fn y => x <= y)
val test0 = (is_sorted 1) 2
val is_sorted = fn : int -> int -> bool
val test0 = true : bool
In the SML document, it states that:
filter f l
applies f to each element x of l, from left to right, and returns the list of those x for which f x evaluated to true, in the same order as they occurred in the argument list.
So it is a curried function.
In the SML document, the filter function in the List structure listed as
filter f l
where it takes curried arguments f and l
Instead of passing the arguments in a tuple, you have to provide a function and the list separated by spaces. The answer will be like this
fun only_capitals (xs: string list) =
List.filter (fn s => Char.isUpper(String.sub(s,0))) xs