SML/NJ while loop - while-loop

I am really new to SML and I can't figure out how to get answer for the same;
It goes something like: 3^4 < 32 but 3^5 > 32 so my answer is 4 (power of 3), similarly if I have numbers 4 and 63 then 4^2<63 but 4^3>63 so my answer is 2(power of 4).
I have come up with the following code
val log (b, n) =
let
val counter = ref b
val value = 0
in
while !counter > n do
( counter := !counter*b
value := !value + 1)
end;
So here value is what I need as my answer but I get a lot of errors. I know I am wrong at many places. Any help would be appreciated.
I can perhaps do this the normal ML way but I want to learnt impure ML also...
fun loghelper(x,n,b) = if x>n then 0 else (1+loghelper((x*b),n,b));
fun log(b,n) = loghelper(b,n,b);
ok so finally here is the correct code for the while loop and it works as well;
fun log (b, n) =
let
val counter = ref b
val value = ref 0
in
while (!counter <= n) do
(counter := !counter*b;
value := !value + 1);
!value
end;

You have several problems in your code:
Errors:
Instead of val log (b, n) = it should be fun log (b, n) =. fun is a convenience syntax that lets you define functions easily. If you wanted to write this with val you would write: val log = fn (b, n) => (it gets more complicated in the cases of recursive functions or functions with multiple curried arguments)
You need a semicolon to separate two imperative statements: ( counter := !counter*b;
value := !value + 1)
value needs to be a ref: val value = ref 0
Logic:
Your function doesn't return anything. A while loop has the unit type, so your function returns () (unit). You probably want to return !value. To do this, you need to add a semicolon after the whole while loop thing, and then write !value
Your while loop condition doesn't really make sense. It seems reversed. You probably want while !counter <= n do
Your base case is not right. Either value should start at 1 (since counter starts at b, and b is b to the first power); or counter should start at 1 (since b to the zeroth power is 1). The same issue exists with your functional version.

Related

My take on Migratory Bird is failing one case

Update: I completely overlooked the complexity added by arr.sort() method. So in Kotlin for array of Int, It compiles to use java.util.DualPivotQuicksort see this which in turn has complexity of O(n^2). see this. Other than that, this is also a valid approach.
I know It can be solved by keeping multiple arrays or using collections (which is what I ended up submitting), I want to know what I missed in the following approach
fun migratoryBirds(arr: Array<Int>): Int {
var maxCount = 0
var maxType = 0
var count = 0
var type = 0
arr.sort()
println(arr.joinToString(" "))
for (value in arr){
if (type != value){
if (count > maxCount){
maxCount = count
maxType = type
}
// new count values
type = value
count = 1
} else {
count++
}
}
return maxType
}
This code passes every scenario except for Test case 2 which has 73966 items for array. On my local machine, that array of 73k+ elements was causing timeout but I did test for array up-to 20k+ randomly generated value 1..5 and every time it succeeded. But I couldn't manage to pass Test case 2 with this approach. So even though I ended up submitting an answer with collection stream approach, I would really like to know what could I be missing in above logic.
I am running array loop only once Complexity should be O(n), So that could not be reason for failing. I am pre-sorting array in ascending order, and I am checking for > not >=, therefore, If two types end up having same count, It will still return the lower of the two types. And this approach is working correctly even for array of 20k+ elements ( I am getting timeout for anything above 25k elements).
The reason it is failing is this line
arr.sort()
Sorting an array takes O(n logn) time. However using something like a hash map this can be solved in O(n) time.
Here is a quick python solution I made to give you the general idea
# Complete the migratoryBirds function below.
def migratoryBirds(arr):
ans = -1
count = -1
dic = {}
for x in arr:
if x in dic:
dic[x] += 1
else:
dic[x] = 1
if dic[x] > count or dic[x] == count and x < ans:
ans = x
count = dic[x]
return ans

Why does `variable++` increment the variable but `variable + 1` does not?

Here's the problem in which I encountered this issue:
The function should compare the value at each index position and score a point if the value for that position is higher. No point if they are the same. Given a = [1, 1, 1] b = [1, 0, 0] output should be [2, 0]
fun compareArrays(a: Array<Int>, b: Array<Int>): Array<Int> {
var aRetVal:Int = 0
var bRetVal:Int = 0
for(i in 0..2){
when {
a[i] > b[i] -> aRetVal + 1 // This does not add 1 to the variable
b[i] > a[i] -> bRetVal++ // This does...
}
}
return arrayOf(aRetVal, bRetVal)
}
The IDE even says that aRetVal is unmodified and should be declared as a val
What others said is true, but in Kotlin there's more. ++ is just syntactic sugar and under the hood it will call inc() on that variable. The same applies to --, which causes dec() to be invoked (see documentation). In other words a++ is equivalent to a.inc() (for Int or other primitive types that gets optimised by the compiler and increment happens without any method call) followed by a reassignment of a to the incremented value.
As a bonus, consider the following code:
fun main() {
var i = 0
val x = when {
i < 5 -> i++
else -> -1
}
println(x) // prints 0
println(i) // prints 1
val y = when {
i < 5 -> ++i
else -> -1
}
println(y) // prints 2
println(i) // prints 2
}
The explanation for that comes from the documentation I linked above:
The compiler performs the following steps for resolution of an operator in the postfix form, e.g. a++:
Store the initial value of a to a temporary storage a0;
Assign the result of a.inc() to a;
Return a0 as a result of the expression.
...
For the prefix forms ++a and --a resolution works the same way, and the effect is:
Assign the result of a.inc() to a;
Return the new value of a as a result of the expression.
Because
variable++ is shortcut for variable = variable + 1 (i.e. with assignment)
and
variable + 1 is "shortcut" for variable + 1 (i.e. without assignment, and actually not a shortcut at all).
That is because what notation a++ does is actually a=a+1, not just a+1. As you can see, a+1 will return a value that is bigger by one than a, but not overwrite a itself.
Hope this helps. Cheers!
The equivalent to a++ is a = a + 1, you have to do a reassignment which the inc operator does as well.
This is not related to Kotlin but a thing you'll find in pretty much any other language

Difference between fold and reduce in Kotlin, When to use which?

I am pretty confused with both functions fold() and reduce() in Kotlin, can anyone give me a concrete example that distinguishes both of them?
fold takes an initial value, and the first invocation of the lambda you pass to it will receive that initial value and the first element of the collection as parameters.
For example, take the following code that calculates the sum of a list of integers:
listOf(1, 2, 3).fold(0) { sum, element -> sum + element }
The first call to the lambda will be with parameters 0 and 1.
Having the ability to pass in an initial value is useful if you have to provide some sort of default value or parameter for your operation. For example, if you were looking for the maximum value inside a list, but for some reason want to return at least 10, you could do the following:
listOf(1, 6, 4).fold(10) { max, element ->
if (element > max) element else max
}
reduce doesn't take an initial value, but instead starts with the first element of the collection as the accumulator (called sum in the following example).
For example, let's do a sum of integers again:
listOf(1, 2, 3).reduce { sum, element -> sum + element }
The first call to the lambda here will be with parameters 1 and 2.
You can use reduce when your operation does not depend on any values other than those in the collection you're applying it to.
The major functional difference I would call out (which is mentioned in the comments on the other answer, but may be hard to understand) is that reduce will throw an exception if performed on an empty collection.
listOf<Int>().reduce { x, y -> x + y }
// java.lang.UnsupportedOperationException: Empty collection can't be reduced.
This is because .reduce doesn't know what value to return in the event of "no data".
Contrast this with .fold, which requires you to provide a "starting value", which will be the default value in the event of an empty collection:
val result = listOf<Int>().fold(0) { x, y -> x + y }
assertEquals(0, result)
So, even if you don't want to aggregate your collection down to a single element of a different (non-related) type (which only .fold will let you do), if your starting collection may be empty then you must either check your collection size first and then .reduce, or just use .fold
val collection: List<Int> = // collection of unknown size
val result1 = if (collection.isEmpty()) 0
else collection.reduce { x, y -> x + y }
val result2 = collection.fold(0) { x, y -> x + y }
assertEquals(result1, result2)
Another difference that none of the other answers mentioned is the following:
The result of a reduce operation will always be of the same type (or a super type) as the data that is being reduced.
We can see that from the definition of the reduce method:
public inline fun <S, T : S> Iterable<T>.reduce(operation: (acc: S, T) -> S): S {
val iterator = this.iterator()
if (!iterator.hasNext()) throw UnsupportedOperationException("Empty collection can't be reduced.")
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(accumulator, iterator.next())
}
return accumulator
}
On the other hand, the result of a fold operation can be anything, because there are no restrictions when it comes to setting up the initial value.
So, for example, let us say that we have a string that contains letters and digits. We want to calculate the sum of all the digits.
We can easily do that with fold:
val string = "1a2b3"
val result: Int = string.fold(0, { currentSum: Int, char: Char ->
if (char.isDigit())
currentSum + Character.getNumericValue(char)
else currentSum
})
//result is equal to 6
reduce - The reduce() method transforms a given collection into a single result.
val numbers: List<Int> = listOf(1, 2, 3)
val sum: Int = numbers.reduce { acc, next -> acc + next }
//sum is 6 now.
fold - What would happen in the previous case of an empty list? Actually, there’s no right value to return, so reduce() throws a RuntimeException
In this case, fold is a handy tool. You can put an initial value by it -
val sum: Int = numbers.fold(0, { acc, next -> acc + next })
Here, we’ve provided initial value. In contrast, to reduce(), if the collection is empty, the initial value will be returned which will prevent you from the RuntimeException.
Simple Answer
Result of both reduce and fold is "a list of items will be transformed into a single item".
In case of fold,we provide 1 extra parameter apart from list but in case of reduce,only items in list will be considered.
Fold
listOf("AC","Fridge").fold("stabilizer") { freeGift, itemBought -> freeGift + itemBought }
//output: stabilizerACFridge
In above case,think as AC,fridge bought from store & they give stabilizer as gift(this will be the parameter passed in the fold).so,you get all 3 items together.Please note that freeGift will be available only once i.e for the first iteration.
Reduce
In case of reduce,we get items in list as parameters and can perform required transformations on it.
listOf("AC","Fridge").reduce { itemBought1, itemBought2 -> itemBought1 + itemBought2 }
//output: ACFridge
The difference between the two functions is that fold() takes an initial value and uses it as the accumulated value on the first step, whereas the first step of reduce() uses the first and the second elements as operation arguments on the first step.

Tail Recursion and Iteration SML

This is my assignment.
(http://prnt.sc/aa3gwd)
I've been working on this one with a tutor and this is what we have come up with so far.
fun mult(a,b) =
let
val product = 0
in
if (a = 0) then
0
else
while a > 0 do
(
product := product + b;
if (a = 1) then
product
else
a:= a -1
);
end;
; //the function did not run at end;, so we added these two semicolons below
;
Output of this is:
stdIn:102.11-103.6 Error: syntax error: deleting SEMICOLON END SEMICOLON
I've only been introduced to SML in the last 2 weeks and I just can't get my head around it. Any help is very much appreciated.
You need two (mutable) reference variables; one for the product and one for the counter.
Something like this:
fun mult(a, b) =
let val product = ref 0
val counter = ref a
in
while !counter > 0 do (
product := !product + b;
counter := !counter - 1
);
!product
end;
(This isn't exactly a translation of the recursive code you linked to, because that code was unnecessarily complicated. You may need to adjust, depending on your professor.)
(I would write the recursive version more like this:
fun mult (0, _) = 0
| mult (_, 0) = 0
| mult (a, b) = b + mult(a - 1, b);
It's unclear why the exercise has a special case for a = 1.)

Generalizing functions in F#

I need a function that produces primes in F#. I found this:
let primesSeq =
let rec nextPrime n p primes =
if primes |> Map.containsKey n then
nextPrime (n + p) p primes
else
primes.Add(n, p)
let rec prime n primes =
seq {
if primes |> Map.containsKey n then
let p = primes.Item n
yield! prime (n + 1) (nextPrime (n + p) p (primes.Remove n))
else
yield n
yield! prime (n + 1) (primes.Add(n * n, n))
}
prime 2 Map.empty
This works very well, but sometimes I need to work with int64/BigInts as well. Is there a more clever way of reusing this code than providing another sequences like these:
let primesSeq64 = Seq.map int64 primesSeq
let primesBigInts = Seq.map (fun (x : int) -> BigInteger(x)) primesSeq
I've heard about modifying a code using "inline" and "LanguagePrimitives", but all I've found was connected with function while my problem is related to a value.
Moreover - I'd like to have a function that works with integer types and computes a floor of a square root.
let inline sqRoot arg = double >> Math.Sqrt >> ... ?
but I can't see a way of returning the same type as "arg" is, as Math.Sqrt returns a double. Again - is there anything better than reimplementing the logic that computes a square root by myself ?
So the general way to do this requires a function and languageprimitives - in your case everywhere you have 1 you write LanguagePrimitives.GenericOne which will produce 1 or 1.0 etc depending on what is required.
To get this to work, you need to create a function value - you can avoid this by doing something like:
let inline primesSeq() = ...
let primesintSeq = primesSeq() //if you use this as an int seq later the compiler will figure it out, otherwise you use
let specified : int seq = primesSeq()
I am not so sure about the sqrt case though - it probably depends on how hacky you are willing to make the solution.
A naïve implementation of generic sqRoot may go along these lines:
let sqRoot arg =
let inline sqrtd a = (double >> sqrt) a
let result = match box(arg) with
| :? int64 as i -> (sqrtd i) |> int64 |> box
| :? int as i -> (sqrtd i) |> int |> box
// cases for other relevant integral types
| _ -> failwith "Unsupported type"
unbox result
and then, checking in FSI:
> let result: int = sqRoot 4;;
val result : int = 2
> let result: int64 = sqRoot 9L;;
val result : int64 = 3L