let val declarations in SML NJ - smlnj

I'm having a mental roadblock in understanding how this works and hoping I can get some guidance. The function f below will sort a list of ints (f [1,2,3]). The part I'm stuck on is the val declaration and what is occurring in recursion. I know the val declaration will allow me to compare the second value in the list to the first but I'm getting confused with the list concatenation. It seems like the function would just compare the first two values and then tack on the rest of the list (ie x :: y :: ys). I'm not sure how f ls is actually working. Is it that...
1) The first two values are compared and added to the list
2) then f ls is recursively called?
Seems like that is the case but then I'm confused about the "ys" - seems like the end of the list is tacked on with each call. I know the sort works but not sure how it's actually working.
fun f ([x]) = [x]
| f(x :: ls) =
let
val (y :: ys) = f ls
in
if y > x then x :: y :: ys
else
y :: x :: ys
end
EDIT - Thought about this some more, is it that y::ys within in the in / end body is actually what is being called recursively? If so, SML is smart enough to know that it should use x::ys in y::ys place if it hits else?

First and foremost, the sort doesn't work when the list is very random, e.g. f [2,3,4,1,2,4,6,0,6,7]
Secondly, to answer your question as to how this particular function works,
you can visualize it easily with following print additions to your code:
fun f ([x]) = [x]
| f(x :: ls) = (print( (Int.toString (x)) ^ "\n");
let
val (y :: ys) = f ls
val x_str = Int.toString (x)
val y_str = Int.toString (y)
val ys_str = concat (map Int.toString ys);
val y_gt_x = if y > x then " ---> this one applies " else ""
val x_gt_y = if x >= y then " ---> this one applies " else ""
in
(print ("if " ^ y_str ^ " > " ^ x_str ^
"\n then " ^ x_str ^ " :: " ^ y_str ^ ys_str ^ y_gt_x ^
"\n else " ^ y_str ^ " :: " ^ x_str ^ ys_str ^ x_gt_y ^ "\n");
if y > x then x :: y :: ys
else
y :: x :: ys)
end)
which for the above random list outputs the following:
- f [2,3,4,1,2,4,6,0,6,7];
2
3
4
1
2
4
6
0
6
if 7 > 6
then 6 :: 7 ---> this one applies
else 7 :: 6
if 6 > 0
then 0 :: 67 ---> this one applies
else 6 :: 07
if 0 > 6
then 6 :: 067
else 0 :: 667 ---> this one applies
if 0 > 4
then 4 :: 0667
else 0 :: 4667 ---> this one applies
if 0 > 2
then 2 :: 04667
else 0 :: 24667 ---> this one applies
if 0 > 1
then 1 :: 024667
else 0 :: 124667 ---> this one applies
if 0 > 4
then 4 :: 0124667
else 0 :: 4124667 ---> this one applies
if 0 > 3
then 3 :: 04124667
else 0 :: 34124667 ---> this one applies
if 0 > 2
then 2 :: 034124667
else 0 :: 234124667 ---> this one applies
val it = [0,2,3,4,1,2,4,6,6,7] : int list
-
As you can see, the function f recursively calls itself in the let binding section. (check the code:
let
val (y :: ys) = f ls
as you can see, f ls is the recursive call of the function f, so your analysis of y :: ys being the recursive call within the in body is incorrect as that is merely an operation of prepending the element y to the list ys)
The in body does not get evaluated except all the way at the end of the list. So the in body will first evaluate the last two elements of the list, e.g. 7 > 6 and grow the list ys accordingly.
Thirdly, to answer point number one as to why the sort function f doesn't work properly is because it keeps on adding new elements to ys without seeing if the new elements are placed in order in ys with respect to the remainder elements. Yes, the first element of the list ys gets compared with the new element to be prepended and accordingly the biggest of the two will get prepended first to the remainder of ys, but that doesn't guarantee the correct placement with regards to the second and third and so on element of ys.

Related

add two numbers represented by linked list in scala

I am new to scala and want to write a code that add two numbers represented by linked list in scala as per the below given example
Input:
First List: 5->6->3 // represents number 365
Second List: 8->4->2 // represents number 248
Output
Resultant list: 3->1->6 // represents number 613
I have implemented a code of mutable singly linked list in scala for adding,updating and inserting elements to linked list. Find my code below
class SinglyLinkedList[A] extends ListADT[A] {
private class Node(var data: A,var next: Node)
private var head: Node = null
def apply(index: Int): A = {
require(index >= 0)
var rover = head
for (i <- 0 until index) rover = rover.next
rover.data
}
def update(index: Int,data: A): Unit = {
require(index >= 0)
var rover = head
for (i <- 0 until index) rover = rover.next
rover.data = data
}
def insert(index: Int,data: A): Unit = {
require(index >= 0)
if(index == 0) {
head = new Node(data, head)
}
else{
var rover = head
for (i <- 0 until index-1)
rover = rover.next
rover.next = new Node(data, rover.next)
}
}
def remove(index: Int): A = {
require(index >= 0)
if(index == 0){
val ret = head.data
head = head.next
ret
} else {
var rover = head
for (i <- 0 until index-1) rover = rover.next
val ret = rover.next.data
rover.next = rover.next.next
ret
}
}
}
Can anyone let me know how I am going to perform the addition of two numbers represented by linked list.
How does addition works? I mean the addition on paper: one number under the other?
Let's try for 465 + 248
465
+ 248
---
We start with the least significant digits: 5 + 8. But 5 + 8 = 13, so the result won't fit into a single digit. Which is why we do just like a teacher in preschool taught us: we leave the unit digit and carry the tens digit to the next column
1
465
+ 248
---
3
Now tens. 6 + 4 + (carried) 1 = 11. Again, we leave 1 and carry 1 to the next column:
11
465
+ 248
---
13
And the last column. 4 + 2 + 1 = 7.
11
465
+ 248
---
713
Thus result is 713. If one these 2 numbers have more column or you would carry in the last addition, you could just rewrite remaining numbers.
With immutable liked list it would work the same way (I'll explain in a moment why I used immutable):
take both lists
take heads of both lists (if one of them is empty, you can just return the other as a result of addition)
add heads, and split the result into carry and current digit (carry would be 0 or 0, digit 0 to 9)
if there is carry > 0 add list carry :: Nil to one of tails recursively
prepend digit to recursively added tails
You should end up with something like that:
val add: (List[Int], List[Int]) => List[Int] = {
case (a :: as, b :: bs) =>
val digit = (a + b) % 10
val carry = (a + b) / 10
if (carry > 0) digit :: add(add(as, carry :: Nil), bs)
else digit :: add(as, bs)
case (as, Nil) => as
case (Nil, bs) => bs
}
add(5 :: 6 :: 4 :: Nil, 8 :: 4 :: 2 :: Nil) // 3 :: 1 :: 7 :: Nil
Now, if you would use mutable list it would get trickier. If you want to use mutable list you want to update one of them, right? Which one - first? Second? Both? Your algorithm might calculate the right result but butcher the input.
Let's say you always add the second list to the fist one, and you want to leave the second intact. If the second list is longer, and you would have to add some new places for digits, you have to copy all remaining segments (otherwise you could e.g. update one number in second list and change the first one). You would also have to handle the corner case with carry.
Quite counter-intuitive behavior - numbers are not mutable, and you want to represent numbers.
Try this:
def add(a: List[Int], b: List[Int], o: Int): List[Int] = (a,b,o) match {
case (x::xs, y::ys, d) =>
val v = d + x + y
(v%10)::add(xs, ys, v/10)
case (Nil, Nil, 0) => Nil
case (Nil, Nil, d) => d::Nil
case (xs, Nil, d) => add(xs, 0::Nil, d)
case (Nil, ys, d) => add(0::Nil, ys, d)
}

Adding elements to a list in a for loop

var locations: List[Location] = List[Location]()
for (x <- 0 to 10; y <- 0 to 10) {
println("x: " + x + " y: " + y)
locations ::: List(Location(x, y))
println(locations)
}
The code above is supposed to concatenate some lists. But the result is an empty list. Why?
Your mistake is on the line locations ::: List(Location(x, y)). This is concatenating the lists, but the doing nothing with the result. If you replace it with locations = locations ::: List(Location(x, y)) you would have your desired result.
However there are more idiomatic ways to solve this problem in Scala. In Scala, writing immutable code is the preferred style (i.e. use val rather than var where possible).
Here's a couple of ways to do it:
Using yield:
val location = for (x <- 0 to 10; y <- 0 to 10) yield Location(x, y)
Using tabulate:
val location = List.tabulate(11, 11) { case (x, y) => Location(x, y) }
Even shorter:
val location = List.tabulate(11, 11)(Location)
Edit: just noticed you had 0 to 10 which is inclusive-inclusive. 0 until 10 is inclusive-exclusive. I've changed the args to tabulate to 11.

Accessing the Accumulator & Element in `foldl`

In Scala's foldLeft, I know how to access the accumulator and element values in Scala, but not Haskell.
I could use foldLeft to find out, between 1 and 100, how many numbers have a remainder of 1 when divided by 3:
scala> List.range(1, 101).foldLeft(0){ (acc, elem) =>
| if (elem % 3 == 1) acc + 1
| else acc
| }
res2: Int = 33
How can I do the same in Haskell?
There's essentially a 1-to-1 correspondence:
mySum :: [Int] -> Int
mySum xs = foldl (\acc elem ->
if elem `mod` 3 == 1
then acc + 1
else acc
) 0 xs
Other than syntax and order of arguments, there's no real difference.
For future readers, it is recommended to avoid using foldl in practice. Due to laziness in foldl's implementation, space leaks can occur for large lists. Instead, there is a strict version foldl' which can be used as a drop-in replacement or the right fold foldr which has a bit format:
mySum xs = foldr (\elem acc -> -- order of arguments swapped
if elem `mod` 3 == 1
then acc + 1
else acc
) 0 xs
This is a direct translation of your Scala code to Haskell:
foldl (\acc x -> if x `mod` 3 == 1 then acc + 1 else acc) 0 [1..100]
In Haskell, because of laziness of it, using foldl usually is not a good idea, a better choose is foldl' or foldr, here is the foldr version:
foldr (\x acc -> if x `mod` 3 == 1 then acc + 1 else acc) 0 [1..100]
It's rather similar:
foldl (\acc x -> if (x `mod` 3 == 1) then acc + 1 else acc) 0 [1..100]
The first argument to foldl is the lambda, the second is the accumulator 0 and the third is the range of values.
Refer to this question to understand the differences between foldl, foldl' and foldr.

How to understand function reduceLeft?

Why can (1 :: xs) be inserted?
One is cons'd onto beginning of list xs.
So List(3,2,1) becomes List(1,3,2,1) but what is significance of (1 :: xs)?
I'm having trouble understanding how this works :
def product(xs : List[Int]) = (1 :: xs) reduceLeft((x , y) => x * y)
In method signature a prefix operand (in this case (1 :: xs)) is not described? :
def reduceLeft[B >: A](f: (B, A) => B): B =
(1 :: xs) is not a prefix operand.
You are actually adding 1 before your list xs.
So product(List(3,2,1)) becomes List(1,3,2,1) reduceLeft((x,y) => x * y).
The reduceLeft function will take the 2 elements on the left and replace by the result of your function (x,y) => x * y.
In your case
List(1,3,2,1) => takes (1,3) and replaces by 1* 3 = 3 new List: List(3,2,1)
List(3,2,1) => takes (3,2) and replaces by 3 *2 = 6 new List: (6,1)
Finally takes (6,1) and get the final result 6.
As multiplying by one has no effect in the product, we add the number 1 before the List to avoid an error if the List is Empty.
Remove that and try product(List()) and you will see. If the List had at least on element (1::xs) will have no effect in your function
I believe you understand cons just fine. (1 :: xs) is simply another way to express List(1,3,2,1), on which you then invoke reduceLeft.
As for a better understanding of reduceLeft, I recently blogged this exact topic.
That's not a prefix operand--it's a method invocation on a List instance. The method reduceLeft is being called on the List (1 :: xs).
(1 :: xs) reduceLeft((x , y) => x * y)
can also be written as
(1 :: xs).reduceLeft((x , y) => x * y)
Or, even more explicitly:
val myList = (1 :: xs)
myList.reduceLeft((x , y) => x * y)

syntax explanation for pattern matching a list in scala

I was reading this blog post and i was not able to understand a part of the code.
object O {
def maximum(x: List[Int]): Int = x match {
case Nil => error("maximum undefined for empty list")
case x :: y :: ys => maximum((if(x > y) x else y) :: ys)
case x :: _ => x
}
}
Please explain the code maximum((if(x > y) x else y) :: ys)
How the if condition can be a part of the method maximum ?
I understand that if condition is not exactly a parameter.
In Scala, if is an expression, not a statement.
Try this in the REPL:
scala> val x=1; val y=0
x: Int = 1
y: Int = 0
scala> val test=if(x > y) x else y
test: Int = 1
if evaluates to 1 and 1 is assigned to test. In Java if could be expressed with the conditional operator (x > y) ? x : y
Now, you have a function called maximum that takes a List[Int] as a parameter.
maximum((if(x > y) x else y) :: ys) calls maximum (recursively) with a list obtained prepending one between x and y (depending on what the if evaluates to) to ys.