SML currying and recursion - sml

I'm writing functions to return max and min of a list
Since the code is the same except for one function call, I'm trying to not duplicate code
fun cur f f2 x=case x of
[]=>raise Empty
|[x]=>x
|x::xs=>f(x,f2(xs))
fun min x=cur Int.min min x
fun max x=cur Int.max max x
it feels having min refer to itself in declaration isn't good style
Any suggestions on how to improve the code?

Note that fun is recursive by default. Thus you are correct you don't need to make an explicit recursive reference:
fun cur f x = case x of
[] => raise Empty
| [x] => x
| x::xs => f(x, cur f xs)
fun min x = cur Int.min x
fun max x = cur Int.max x
This is a general case of a fold. Take a look at foldr and foldl in the standard library. There are also more efficient ways to do this, in particular by making your function tail recursive. That is always a nice exercise!

Related

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?

How to sort a list in Haskell in command line ghci

I am new to Haskell, and I want to make 1 function that will take two lists and merge then together, and then sort the combined list from smallest to biggest.
this should be done in the command line without using modules.
This is what i currently have, I am having trouble getting the "sortList" function to work, and also I do not know how to combine these 3 lines into 1 function.
let combineList xs ys = xs++ys
let zs = combineList xs ys
let sortList (z:zs) = if (head zs) < z then (zs:z) else (z:(sortList zs))
How to sort list in ghci:
Prelude> :m + Data.List
Prelude Data.List> sort [1,4,2,0]
[0,1,2,4]
About your functions
let combineList xs ys = xs++ys
What is a point to create another alias for append function? But if you're really wants one - it could be defined like let combineList = (++).
let zs = combineList xs ys
It makes no sense because xs and ys are unknown outside of your combineList.
let sortList (z:zs) = if (head zs) < z then (zs:z) else (z:(sort zs))
This definition is not valid because it doesn't cover and empty list case and (zs:z) produces infinite type and sort is not defined yet. And you can get head of zs just by another pattern matching. And maybe you don't wanna to make another recursive call in the then part of if statement. And finally I should admit that this sorting algorithm doesn't work at all.
It's a bit awkward to define a sorting function within the ghci. I thing the easiest way to do it would be to write the sorting function in a file, and then loading it into ghci. For instance, you could write this concise (though not in-place!) version of quicksort in a file called sort.hs (taken from the HaskellWiki):
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
where
lesser = filter (< p) xs
greater = filter (>= p) xs
and load it into ghci:
> :l sort.hs
If you really want to define the function in ghci, you can do something like this (from the Haskell user's guide):
> :{
> let { quicksort [] = []
> ; quicksort (p:xs) = (quicksort (filter (< p) xs)) ++ [p] ++ (quicksort (filter (>= p) xs))
> }
> :}
once this is defined, you can do
> let combineAndSort xs ys = quicksort (xs ++ ys)
As another answer already explained, it would of course be quicker to just import sort from Data.List, but it is definitely a good exercise to do it manually.
Your question suggests that you are a bit confused about the scope of variables in Haskell. In this line
> let combineList xs ys = xs++ys
you introduce the variables xs and ys. Mentioning them to the left of the equals sign just means that combineList takes two variables, and in the body of that function, you are going to refer to these variables as xs and ys. It doesn't introduce the names outside of the function, so the next line
> let zs = combineList xs ys
doesn't really make sense, because the names xs and ys are only valid within the scope of combineList. To make zs have a value, you need to give combineList some concrete arguments, eg.:
> let zs = combineList [2,4,6] [1,3,5] --> [2,4,6,1,3,5]
But since the body of combineList is so simple, it would actually be easier to just do:
> let zs = [2,4,6] ++ [1,3,5] --> [2,4,6,1,3,5]
The last line is
> let sortList (z:zs) = if (head zs) < z then (zs:z) else (z:(sortList zs))
I think this line has confused you a lot, because there are quite a lot of different errors here. The answer by ДМИТРИЙ МАЛИКОВ mentions most of them, I would encourage you to try understand each of the errors he mentions.

filtering values into two lists

So i'm new to sml and am trying to understand the ins/out out of it. Recently i tried creating a filter which takes two parameters: a function (that returns a boolean), and a list of values to run against the function. What the filter does is it returns the list of values which return true against the function.
Code:
fun filter f [] = [] |
filter f (x::xs) =
if (f x)
then x::(filter f xs)
else (filter f xs);
So that works. But what i'm trying to do now is just a return a tuple that contains the list of true values, and false. I'm stuck on my conditional and I can't really see another way. Any thoughts on how to solve this?
Code:
fun filter2 f [] = ([],[]) |
filter2 f (x::xs) =
if (f x)
then (x::(filter2 f xs), []) (* error *)
else ([], x::(filter2 f xs)); (* error *)
I think there are several ways to do this.
Reusing Filter
For instance, we could use a inductive approach based on the fact that your tuple would be formed by two elements, the first is the list of elements that satisfy the predicate and the second the list of elements that don't. So, you could reuse your filter function as:
fun partition f xs = (filter f xs, filter (not o f) xs)
This is not the best approach, though, because it evaluates the lists twice, but if the lists are small, this is quite evident and very readable.
Folding
Another way to think about this is in terms of fold. You could think that you are reducing your list to a tuple list, and as you go, you split your items depending on a predicate. Somwewhat like this:
fun parition f xs =
let
fun split x (xs,ys) =
if f x
then (x::xs,ys)
else (xs, x::ys)
val (trueList, falseList) = List.foldl (fn (x,y) => split x y)
([],[]) xs
in
(List.rev trueList, List.rev falseList)
end
Parition
You could also implement your own folding algorithm in the same way as the List.parition method of SML does:
fun partition f xs =
let
fun iter(xs, (trueList,falseList)) =
case xs of
[] => (List.rev trueList, List.rev falseList)
| (x::xs') => if f x
then iter(xs', (x::trueList,falseList))
else iter(xs', (trueList,x::falseList))
in
iter(xs,([],[]))
end
Use SML Basis Method
And ultimately, you can avoid all this and use SML method List.partition whose documentation says:
partition f l
applies f to each element x of l, from left to right, and returns a
pair (pos, neg) where pos is the list of those x for which f x
evaluated to true, and neg is the list of those for which f x
evaluated to false. The elements of pos and neg retain the same
relative order they possessed in l.
This method is implemented as the previous example.
So I will show a good way to do it, and a better way to do it (IMO). But the 'better way' is just for future reference when you learn:
fun filter2 f [] = ([], [])
| filter2 f (x::xs) = let
fun ftuple f (x::xs) trueList falseList =
if (f x)
then ftuple f xs (x::trueList) falseList
else ftuple f xs trueList (x::falseList)
| ftuple _ [] trueList falseList = (trueList, falseList)
in
ftuple f (x::xs) [] []
end;
The reason why yours does not work is because when you call x::(filter2 f xs), the compiler is naively assuming that you are building a single list, it doesn't assume that it is a tuple, it is stepping into the scope of your function call. So while you think to yourself result type is tuple of lists, the compiler gets tunnel vision and thinks result type is list. Here is the better version in my opinion, you should look up the function foldr if you are curious, it is much better to employ this technique since it is more readable, less verbose, and much more importantly ... more predictable and robust:
fun filter2 f l = foldr (fn(x,xs) => if (f x) then (x::(#1(xs)), #2(xs)) else (#1(xs), x::(#2(xs)))) ([],[]) l;
The reason why the first example works is because you are storing default empty lists that accumulate copies of the variables that either fit the condition, or do not fit the condition. However, you have to explicitly tell SML compiler to make sure that the type rules agree. You have to make absolutely sure that SML knows that your return type is a tuple of lists. Any mistake in this chain of command, and this will result in failure to execute. Hence, when working with SML, always study your type inferences. As for the second one, you can see that it is a one-liner, but I will leave you to research that one on your own, just google foldr and foldl.

How do I find largest number in List in SML

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?)
What I have done is find the largest number by comparison from the beginning.
How can I do it from the end? What logic should I apply?
Here is my code for comparing from the beginning.
- fun largest[x] = x
= | largest(x::y::xs) =
= if x>y then largest(x::xs) else largest(y::xs)
= | largest[] = 0;
val largest = fn : int list -> int
output
- largest [1,4,2,3,6,5,4,6,7];
val it = 7 : int
In your function, first two elements of the list are compared and the bigger value is compared to the remaining elements. I think comparison from the end means that you try to find the largest number of the tail of the list first and compare it with the head element later.
fun largest [] = raise Empty
| largest [x] = x
| largest (x::xs) =
let
val y = largest xs
in
if x > y then x else y
end
Although it is not required, you should handle the case of empty list for completeness. And you can shorten the function if using max function.
fun largest [] = raise Empty
| largest [x] = x
| largest (x::xs) = max(x, largest xs)
To be honest, I would prefer your version which is tail-recursive (it doesn't blow the stack on big lists). My function could be rewritten to be tail-recursive as other answers demonstrated, but certainly it is more sophisticated than your function.
As #pad demonstrates with his code, the logic that should be applied is making a recursive call that solves the sub-problem recursively before solving the problem of the current scope of the function.
In the case of largest, there is not really any point in solving it backwards, since it simply uses more stack space, which becomes apparent when executing the code "by hand". The design pattern is however useful in other situations. Imagine a function called zip:
(* zip ([1,2,3,4], [a,b,c]) = [(1,a),(2,b),(3,c)] *)
fun zip (x::xs, y::ys) = (x,y) :: zip (xs, ys)
| zip _ = []
This function turns a tuple of two lists into a list of many tuples, discarding left-over values. It may be useful in circumstances, and defining it is not that bad either. Making its counterpart, unzip, is however slightly trickier:
(* unzip ([(1,a),(2,b),(3,c)] = ([1,2,3],[a,b,c]) *)
fun unzip [] = ([], [])
| unzip ((x,y)::xys) =
let
val (xs, ys) = unzip xys
in
(x::xs, y::ys)
end
Running the regular "from the beginning"-largest by hand might look like this:
largest [1,4,2,3,6,5,4,6,7]
~> largest [4,2,3,6,5,4,6,7]
~> largest [4,3,6,5,4,6,7]
~> largest [4,6,5,4,6,7]
~> largest [6,5,4,6,7]
~> largest [6,4,6,7]
~> largest [6,6,7]
~> largest [6,7]
~> largest [7]
~> 7
Running the "from the end"-largest by hand, imagining that every indentation level requires saving the current context of a function call in stack memory, calling a new function and returning the result after the ~> arrow, might look like this:
largest [1,4,2,3,6,5,4,6,7] ~> 7
\_
largest [4,2,3,6,5,4,6,7] ~> 7
\_
largest [2,3,6,5,4,6,7] ~> 7
\_
largest [3,6,5,4,6,7] ~> 7
\_
largest [6,5,4,6,7] ~> 7
\_
largest [5,4,6,7] ~> 7
\_
largest [4,6,7] ~> 7
\_
largest [6,7] ~> 7
\_
largest [7] ~> 7
So why are these non-tail-recursive functions that make early recursive calls useful if they simply use more memory? Well, if we go back to unzip and we want to solve it without this annoying "thinking in reverse", we have a problem constructing the new result, which is a tuple, because we don't have anywhere to put the x and y:
(* Attempt 1 to solve unzip without abusing the call stack *)
fun unzip [] = ([], [])
| unzip ((x,y)::xys) = ...something with x, y and unzip xys...
One idea for making such a place would to create an auxiliary function (helper function) that has a few extra function parameters for building xs and ys. When the end of the xys list is reached, those values are returned:
(* Attempt 2 to solve unzip without abusing the call stack *)
local
fun unzipAux ([], xs, ys) = (xs, ys)
| unzipAux ((x,y)::xys, xs, ys) = unzipAux (xys, x::xs, y::ys)
in
fun unzip xys = unzipAux (xys, [], [])
end
But you might have realized that those (xs, ys) end up reversed in the result. A quick way to fix this is by using rev on them, once only, which is best achieved at the base case:
(* Attempt 3 to solve unzip without abusing the call stack *)
local
fun unzipAux ([], xs, ys) = (rev xs, rev ys)
| unzipAux ((x,y)::xys, xs, ys) = unzipAux (xys, x::xs, y::ys)
in
fun unzip xys = unzipAux (xys, [], [])
end
Which brings forth an interesting question: How is rev implemented?
I suggest using a tail recursive helper, which passes the current maximum as an accumulator.
local
fun helper max [] = max
| helper max (n::ns) = helper (if n > max then n else max) ns
in
fun largest ns = helper 0 ns
end;
(*Find the max between two comparable items*)
fun max(a,b) = if a>b then a else b;
(*Find the max item in list which calls the maxL function recursively*)
fun maxL(L) = if L=[] then 0 else max(hd(L), maxL(tl(L)));
I know it is too late to answer your question, but hopefully this will help:
fun insert (x, []) = [x]
| insert (x, y::ys) = if x<=y then x::y::ys else y::insert(x,ys);
fun insertion_sort [] = []
| insertion_sort (x::xs) = insert(x, insertion_sort xs);
fun get_last_element [] = 0
| get_last_element [x] = x
| get_last_element (x::xs) = if(xs=nil)
then x
else
get_last_element(xs);
fun get_min L = if(insertion_sort(L)=[])
then 0
else
hd(insertion_sort(L));
fun get_max L = get_last_element(insertion_sort(L));
You also can tweak the code e.g. passing anonymous function in insert function ...

Using Haskell's map function to calculate the sum of a list

Haskell
addm::[Int]->Int
addm (x:xs) = sum(x:xs)
I was able to achieve to get a sum of a list using sum function but is it possible to get the sum of a list using map function? Also what the use of map function?
You can't really use map to sum up a list, because map treats each list element independently from the others. You can use map for example to increment each value in a list like in
map (+1) [1,2,3,4] -- gives [2,3,4,5]
Another way to implement your addm would be to use foldl:
addm' = foldl (+) 0
Here it is, the supposedly impossible definition of sum in terms of map:
sum' xs = let { ys = 0 : map (\(a,b) -> a + b) (zip xs ys) } in last ys
this actually shows how scanl can be implemented in terms of map (and zip and last), the above being equivalent to foldl (+) 0 xs === last $ scanl (+) 0 xs:
scanl' f z xs = let { ys = z : map (uncurry f) (zip ys xs) } in ys
I expect one can calculate many things with map, arranging for all kinds of information flow through zip.
edit: the above is just a zipWith in disguise of course (and zipWith is kind of a map2):
sum' xs = let { ys = 0 : zipWith (+) ys xs } in last ys
This seems to suggest that scanl is more versatile than foldl.
It is not possible to use map to reduce a list to its sum. That recursive pattern is a fold.
sum :: [Int] -> Int
sum = foldr (+) 0
As an aside, note that you can define map as a fold as well:
map :: (a -> b) -> ([a] -> [b])
map f = fold (\x xs -> f x : xs) []
This is because foldr is the canonical recursive function on lists.
References: A tutorial on the universality and expressiveness of fold, Graham Hutton, J. Functional Programming 9 (4): 355–372, July 1999.
After some insights I have to add another answer: You can't get the sum of a list with map, but you can get the sum with its monadic version mapM. All you need to do is to use a Writer monad (see LYAHFGG) over the Sum monoid (see LYAHFGG).
I wrote a specialized version, which is probably easier to understand:
data Adder a = Adder a Int
instance Monad Adder where
return x = Adder x 0
(Adder x s) >>= f = let Adder x' s' = f x
in Adder x' (s + s')
toAdder x = Adder x x
sum' xs = let Adder _ s = mapM toAdder xs in s
main = print $ sum' [1..100]
--5050
Adder is just a wrapper around some type which also keeps a "running sum." We can make Adder a monad, and here it does some work: When the operation >>= (a.k.a. "bind") is executed, it returns the new result and the value of the running sum of that result plus the original running sum. The toAdder function takes an Int and creates an Adder that holds that argument both as wrapped value and as running sum (actually we're not interested in the value, but only in the sum part). Then in sum' mapM can do its magic: While it works similar to map for the values embedded in the monad, it executes "monadic" functions like toAdder, and chains these calls (it uses sequence to do this). At this point, we get through the "backdoor" of our monad the interaction between list elements that the standard map is missing.
Map "maps" each element of your list to an element in your output:
let f(x) = x*x
map f [1,2,3]
This will return a list of the squares.
To sum all elements in a list, use fold:
foldl (+) 0 [1,2,3]
+ is the function you want to apply, and 0 is the initial value (0 for sum, 1 for product etc)
As the other answers point out, the "normal" way is to use one of the fold functions. However it is possible to write something pretty similar to a while loop in imperative languages:
sum' [] = 0
sum' xs = head $ until single loop xs where
single [_] = True
single _ = False
loop (x1 : x2 : xs) = (x1 + x2) : xs
It adds the first two elements of the list together until it ends up with a one-element list, and returns that value (using head).
I realize this question has been answered, but I wanted to add this thought...
listLen2 :: [a] -> Int
listLen2 = sum . map (const 1)
I believe it returns the constant 1 for each item in the list, and returns the sum!
Might not be the best coding practice, but it was an example my professor gave to us students that seems to relate to this question well.
map can never be the primary tool for summing the elements of a container, in much the same way that a screwdriver can never be the primary tool for watching a movie. But you can use a screwdriver to fix a movie projector. If you really want, you can write
import Data.Monoid
import Data.Foldable
mySum :: (Foldable f, Functor f, Num a)
=> f a -> a
mySum = getSum . fold . fmap Sum
Of course, this is silly. You can get a more general, and possibly more efficient, version:
mySum' :: (Foldable f, Num a) => f a -> a
mySum' = getSum . foldMap Sum
Or better, just use sum, because its actually made for the job.