SML - bidirectional infinite and finite sequence interleaving - sequence

I have the next declarations of datatype and functions:
datatype direction = Back | Forward
datatype 'a bseq = bNil | bCons of 'a * (direction -> 'a bseq)
fun bHead (bCons (x, _)) = x
| bHead bNil = raise EmptySeq
fun bForward(bCons(_, xf)) = xf Forward
| bForward bNil = raise EmptySeq
fun bBack (bCons (_, xf)) = xf Back
| bBack bNil = raise EmptySeq
fun intbseq k =
let fun go Forward = intbseq (k+1)
| go Back = intbseq (k-1)
in bCons (k, go) end
The next function is written by me for interleaving two sequences like that:
if the first seq is ... ,1,2,3,4,5, ..... and the second is ...,5,6,7,8,9,...
The new sequance of their interleaving is:
... ,3,-1,4,0,5,1,6,2,7,3, ......
Code:
fun binterleaving_aux _ bNil yq = yq
| binterleaving_aux _ xq bNil = xq
| binterleaving_aux firstb (bCons(x,xf)) (bCons(y,yf)) =
bCons(x, fn dir =>
if dir = Forward
then binterleaving_aux true (bCons (y, yf)) (xf dir)
else if firstb
then binterleaving_aux false (yf dir) (xf dir)
else binterleaving_aux false (bCons (y,yf)) (xf dir)));
fun binterleaving bseq1 bseq2 = binterleaving_aux true bseq1 bseq2;
And for that exmaple:
binterleaving (intbseq 5) (intbseq 1);
bForward(it);
bForward(it);
bForward(it);
bForward(it);
bBack(it);
bBack(it);
bBack(it);
bBack(it);
It is working great for 2 infinite sequences.
The problem is when at least one of them is finite.
For exmaple if I do:
binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 5);
bForward(it);
bForward(it);
bForward(it);
bForward(it);
bBack(it);
bBack(it);
bBack(it);
bBack(it);
If I go back I lose the 10 and 9, and the opposite if firstly I went back, when I move forward I lose them ether.
The result is by the order of the calls:
val it = bCons (10,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (7,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (4,fn) : int bseq
val it = bCons (3,fn) : int bseq
And the correct result should be:
val it = bCons (10,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (7,fn) : int bseq
val it = bCons (6,fn) : int bseq
val it = bCons (9,fn) : int bseq
val it = bCons (5,fn) : int bseq
val it = bCons (10,fn) : int bseq
What are the changes in the code I should do, so that will be the behavior of the function?

The problem is when at least one of them is finite.
binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 0)
When your finite sequence reduces to bNil, how is it supposed to get back to its original values? The semantics of interleaving a finite sequence with an infinite one seem a little under-defined.
That is, when the finite one ends and the infinite one continues, where is the reference stored along the infinite sequence at which point the finite one starts again in reverse?
Take the example above and evaluate it a few steps (forgive my lazy notation):
binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil)))) (intbseq 0)
⇒ binterleaving (bCons(10, fn dir => bCons((9, fn dir => bNil))))
(bCons( 0, fn dir => ...intbseq (+/- 1)...))
⇒ binterleaving_aux true (bCons(10, fn dir => bCons((9, fn dir => bNil))))
(bCons( 0, fn dir => ...intbseq (+/- 1)...))
⇒ bCons (9, fn dir =>
if dir = Forward
then binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...))
((fn dir => bNil) dir)
else ...)
Evaluating this once by applying Forward to the outermost fn gives:
bCons (9, (fn dir => ...) Forward)
⇒ bCons (9, binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...))
((fn dir => bNil) dir))
⇒ bCons (9, binterleaving_aux true (bCons (0, fn dir => ...intbseq (+/- 1)...)) bNil)
⇒ bCons (9, bCons (0, fn dir => ...intbseq (+/- 1)...))
At this point, there is no trace of the finite sequence 9 in any function capable of going backward. Only in the initial return value of binterleaving.
The fix mainly lies in the base case of binterleaving which throws away the finite sequence. Rather, the result of interleaving an empty sequence with a non-empty sequence should be a non-empty sequence that, when reversed, returns whatever the empty sequence was before it got empty (which was possibly also empty, but possibly non-empty).
You can see your bidirectional sequence as a lazy zipper on lists. The book Learn You a Haskell has a chapter on tree zippers that might be worth a read. In this chapter's terminology, you might want a function that returns a "breadcrumb trail". List zippers are conceptually a bit simpler, but sprinkled with the laziness of 'a bseqs, syntactically not so.

Related

How to destructure Kotlin nested pairs with forEach

I need to destructure Kotlin nested pairs. How can I do this simply without using pair.first/pair.second?
val chars = listOf('A', 'B', 'C')
val ints = listOf(1, 2, 3)
val booleans = listOf(true, false, false)
val cib: List<Pair<Pair<Char, Int>, Boolean>> = chars.zip(ints).zip(booleans)
cib.forEach { ((c, i), b) -> // compile error
println("$c $i $b")
}
Not sure if there really is a way of desctructuring a Pair<Pair<*,*>> straight away, but you could do this:
cib.forEach { (pair, b) ->
val (c, i) = pair
//do stuff with c, i, b
}

Find the list item of Pairs with the minimum value

val index = listOf("abc", "def", "ghi", "jkl", "mno")
.mapIndexed { index, v ->
var t = 0
var p = 0
for (s in v) {
t += ("deh".get(p++).toInt() - s.toInt()).absoluteValue
}
Pair(index, v)
}
.minOf {
val iterator = iterator<Pair<Int, String>>(it)
if (!iterator.hasNext()) throw NoSuchElementException()
var minValue = iterator.next().second
while (iterator.hasNext()) {
val v = selector(iterator.next())
minValue = minOf(minValue, v)
}
return minValue
}
This is an alternative solution and works, but I am wondering if the solution can be done using mapOf as shown above?
val index = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
.mapIndexed { index, v ->
var t = 0
var p = 0
for (s in v) {
t += ("jac".get(p++).toInt() - s.toInt()).absoluteValue
}
Pair(index, t)
}.toSortedSet(compareBy { it.second })
.first()
I create a map of Pairs and I want to find the index of the map item where the Pair with the value (the second item in the pair) is the lowest value (minimum) of all the pairs. If possible, I would like to use the minOf function. The first example above will not compile because of bugs in the minOf function. Not sure how to iterate over the map of Pairs.
You can use minBy {} to get the minimum value from a collection, although often it's safer to use minByOrNull {} in case no minimal value can be computed (which could happen if the list is empty).
import kotlin.math.absoluteValue
fun main() {
val minElement = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
.minByOrNull { v ->
var t = 0
var p = 0
for (s in v) {
t += ("jac".get(p++).toInt() - s.toInt()).absoluteValue
}
t
}
println(minElement)
}
jad
Run in Kotlin Playground
If you also want to find the index of the minimal value, then you can use withIndex(), which will pair each list element with its index.
import kotlin.math.absoluteValue
fun main() {
val minIndexedElement = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
.withIndex() // adds the index to each element
.minByOrNull { (_, v) ->
var t = 0
var p = 0
for (s in v) {
t += ("jac".get(p++).toInt() - s.toInt()).absoluteValue
}
t
}
println(minIndexedElement)
}
IndexedValue(index=4, value=jad)
Run in Kotlin Playground
Another solution would be to extract the character codes from "jar" and from each item, and then to zip the two code lists. zip allows for a transform closure in which the calculation with the two codes can be made. After that sum() gives the wanted value.
data class Result(val index: Int, val string: String, val computedValue: Int)
val list = listOf("abc", "def", "ghi", "jkl", "jad", "jaa", "mno")
val result = list
.mapIndexed { idx, str ->
val codes1 = "jac".toCharArray().map { it.code }
val codes2 = str.toCharArray().map { it.code }
val computed = codes1.zip(codes2) { code1, code2 -> (code1 - code2).absoluteValue }.sum()
Result(idx, str, computed)
}
.minByOrNull { it.computedValue }
println(result) // Output: Result(index=4, string=jad, computedValue=1)
Instead of the helper data class Result a Triple instance could be used:
...
Triple(idx, str, computed)
}
.minByOrNull { it.third }
// Output: (4, jad, 1)
Or if the calculated value is not needed, it could be dropped like that:
...
?.let { it.first to it.second }
// Output: (4, jad)

fold/reduce with complex accumulator

I have a list that looks like this:
val myList = listOf(
Message(
id= 1,
info = listOf(1, 2)
),
Message(
id= 1,
info = listOf(3, 4)
),
Message(
id= 2,
info = listOf(5, 6)
)
)
How can I convert it so the elements with the same id are combined?
listOf(
Message
id= 1
info = listOf(1, 2, 3, 4)
),
Message
id= 2
info = listOf(5, 6)
)
)
I've tried the following, and it works
myList
.groupBy { it.id }
.map { entry ->
val infos = entry.value.fold(listOf<Int>()) { acc, e -> acc + e.info }
Message(
id = entry.key,
info = infos
)
}
But I was wondering if there was an easier/cleaner/more idiomatic way to merge these objects. It seems like I would be able to do this with a single fold, but I can't wrap my brain around it.
Thanks
Would also go for groupingBy but do it a bit differently via fold (compare also Grouping):
myList.groupingBy { it.id }
.fold({ _, _ -> mutableListOf<Int>() }) { _, acc, el ->
acc.also { it += el.info }
}
.map { (id, infos) -> Message(id, infos) }
This way you have only 1 intermediate map and only 1 intermediate list per key, which accumulates your values. At the end you transform it in the form you require (e.g. into a Message). Maybe you do not even need that? Maybe the map is already what you are after?
In that case you may want to use something as follows (i.e. narrowing the mutable list type of the values):
val groupedMessages : Map<Int, List<Int>> = myList.groupingBy { it.id }
.fold({ _, _ -> mutableListOf() }) { _, acc, el ->
acc.also { it += el.info }
}
You can groupingBy the ids, then reduce, which would perform a reduction on each of the groups.
myList.groupingBy { it.id }.reduce { id, acc, msg ->
Message(id, acc.info + msg.info)
}.values
This will of course create lots of Message and List objects, but that's the way it is, since both are immutable. But there is also a chance that this doesn't matter in the grand scheme of things.
If you had a MutableMessage like this:
data class MutableMessage(
val id: Int,
val info: MutableList<Int>
)
You could do:
myList.groupingBy { it.id }.reduce { _, acc, msg ->
acc.also { it.info.addAll(msg.info) }
}.values
A solution without using reduce or fold:
data class Message(val id: Int, val info: List<Int>)
val list = listOf(
Message(id = 1, info = listOf(1, 2)),
Message(id = 1, info = listOf(3, 4)),
Message(id = 2, info = listOf(5, 6))
)
val result = list
.groupBy { message -> message.id }
.map { (_, message) -> message.first().copy(info = message.map { it.info }.flatten() ) }
result.forEach(::println)
By extracting out a few functions which have a meaning of their own, You can make it readable to a great extent.
data class Message(val id: Int, val info: List<Int>) {
fun merge(that: Message): Message = this.copy(info = this.info + that.info)
}
fun List<Message>.mergeAll() =
this.reduce { first, second -> first.merge(second) }
fun main() {
val myList = listOf(
Message(
id = 1,
info = listOf(1, 2)
),
Message(
id = 1,
info = listOf(3, 4)
),
Message(
id = 2,
info = listOf(5, 6)
)
)
val output = myList
.groupBy { it.id }
.values
.map { it.mergeAll() }
println(output)
}

using val in kotlin lambda

i'm playing around with map in kotlin, and currently I would like to see whether it would be possible to map a list of integers to a list of functions (Int) -> Int, while doing a bunch of operations inside the lambda that would require me to save values to vals
So I have this simple code:
val num = arrayOf(1, 2, 3, 4)
val funcs = num.map <Int, (Int) -> Int > { x -> {
y -> y + x
}}
This is a bit of a condensed example, the thing i'm really trying to do is a bit more convoluted. But I need to quite a bit of operations inside of of the 'inner' lambda, so I need to write codeblocks where I can use val. Like this:
val fs = num.map <Int, (Int) -> Int > { x -> {
y -> {
val tmp = y *2
val tmp1 = x / 2
tmp + tmp1
}
}}
But this part doesnt work, the compiler is confused by return types
How can I do something like this?
The reason your code in particular does not work is because you are adding an extra { after y -> in the second example:
val fs = num.map<Int, (Int) -> Int> { x ->
{ y ->
{ // this is not needed
val tmp = y * 2
val tmp1 = x / 2
tmp + tmp1
}// this is not needed
}
}
So you are creating a "block" of {} which in kotlin means that you are creating a lambda function. The reason block is in quotes is because if you truly want a block in kotlin the syntax is run {}, as opposed to the java {}. But again, you do not need it here.
All you have to do is remove the extra brackets and your code is fine:
val fs = num.map <Int, (Int) -> Int > { x -> {
y ->
val tmp = y *2
val tmp1 = x / 2
tmp + tmp1
}}
There is no difference between single-line and multi-line lambda
val fs = num.map { x ->
{ y: Int ->
val tmp = y * 2
val tmp1 = x / 2
tmp + tmp1
}
}

Getting multiple data from model

Hi I would like to get temp, pressure, humidity, temp_min and temp_max and put this informations into separated editText fields.
My search function:
fun search(city: String) {
disposable =
weatherApiService.getWeather(city,apiKey)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{result -> tempTextView.text = "${result.main.temp}"},
{error -> Log.e("searchError", error.message)}
)
}
my model
data class TemperatureFrame(val temp: Double,
val pressure: Double,
val humidity: Int,
val temp_min: Double,
val temp_max: Double)
data class Temperature(val main: TemperatureFrame)
I would like to get something like this for other parameters inside this function
{result -> tempTextView.text = "${result.main.temp}"}
{result -> minTempTextView.text = "${result.main.temp_min}"}
This is working
{result ->
tempTextView.text = "${result.main.temp}"
minTempTextView.text = "${result.main.temp_min}"
},