Flow can't see that my array is not empty? - flowtype

Considering the following code :
const size = 500
const indexes = new Array(size).fill(0).map((_,idx) => idx)
let vals
if (!vals) {
vals = new Array(size).fill(0)
}
indexes.forEach(v => vals[v]++)
Note: I understand this code might look strange. forEaching an array (indexes) and use value as index for another one (vals) might not be usual. But it works and I just tried to make a simple case of a real use-case.
Flow returns this error :
indexes.forEach(v => vals[v]++)
^ access of computed property/element. Computed property/element cannot be accessed on possibly undefined value
indexes.forEach(v => vals[v]++)
^ uninitialized variable
(You can try it on flow.org/try)
to remove the error, I have to change the last line to verify vals on each iteration :
indexes.forEach(v => vals && vals[v] && vals[v]++)
The error vanish also if I replace vals declaration with something initialised immediately
let vals = new Array(size).fill(0)
(So using an array values as indexes to another array doesn't seem to be a problem)
Shouldn't flow be able to understand that vals is defined ?
Thanks for any advice.

Flow is possibly not able to infer the value to that level so you could do like this
const size = 500
let vals
if (!vals) {
vals = new Array(size).fill(0)
}
let newVals = vals
vals.map(v => newVals[v]++)

The problem here isn't because flow thinks the array is empty. It's because flow assumes the conditional initialization is in fact conditional, whereas you know that the if branch will always be executed.
Flow is looking at the types, not the values. (Even though some of the values can be known at compile time)
As far as Flow is concerned,
if (<boolean expression here>) {
vals = new Array(size).fill(0)
}
may or may not initialize vals.
The easiest solution is to remove the unnecessary if to make it clear that vals is always initialized:
const size = 500
const indexes = new Array(size).fill(0).map((_,idx) => idx)
let vals
//if (!vals) {
vals = new Array(size).fill(0)
//}
indexes.forEach(v => vals[v]++)
Try it here
Or even better:
const size = 500
const indexes = new Array(size).fill(0).map((_,idx) => idx)
const vals = new Array(size).fill(0)
indexes.forEach(v => vals[v]++)
Try it here

Related

Why do I get an error when I use transduce?

I am still new to functional programming and have been trying to learn how to use transducers. I thought I had a good use case but every time I attempt to write a transducer with Ramda for it, I get the following error:
reduce: list must be array or iterable
I have tried rewriting it several ways and looked at several explanations on the web of transduction but to no avail. Any suggestions?
const data = [{cost:2,quantity:3},{cost:4,quantity:5},{cost:1,quantity:1}];
const transducer = R.compose(R.map(R.product), R.map(R.props(['cost', 'quantity'])));
const result = R.transduce(transducer, R.add, 0)(data);
console.log(result)
In the context of a transducer, compose reads left to right. You just need to invert product and props:
const data = [
{cost:2,quantity:3},
{cost:4,quantity:5},
{cost:1,quantity:1}];
const transducer =
compose(
map(props(['cost', 'quantity'])),
map(product));
console.log(
transduce(transducer, add, 0, data)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {compose, map, props, product, transduce, add} = R;</script>
The reason why the order reverses is that transducers utilize a property of function composition that is sometimes called abstraction from arity. It simply means that a function composition can return, well, another function:
const comp = f => g => x => f(g(x));
const mapTrace = tag => f => (console.log(tag), xs => (console.log(tag), xs.map(f)));
const sqr = x => x * x;
const main = comp(mapTrace("a")) (mapTrace("b")) (sqr); // returns another function
console.log(main); // logs the 2nd map and then the 1st one (normal order)
// pass an additional argument to that function
console.log(
main([[1,2,3]])); // logs in reverse order
Why returns the composition another function? Because map is a binary function that expects a function argument as its first argument. So when the composition is evaluated it yields another compositon of two partially applied maps. It is this additional iteration that reverses the order. I stop at this point without illustrating the evaluation steps, because I think it would get too complicated otherwise.
Additionally, you can see now how transducers fuse two iterations together: They simply use function composition. Can you do this by hand? Yes, you can absolutely do that.

Scala: Most concise conversion of a CSS color string to RGB integers

I am trying to get the RGB values of a CSS color string and wonder how good my code is:
object Color {
def stringToInts(colorString: String): Option[(Int, Int, Int)] = {
val trimmedColorString: String = colorString.trim.replaceAll("#", "")
val longColorString: Option[String] = trimmedColorString.length match {
// allow only strings with either 3 or 6 letters
case 3 => Some(trimmedColorString.flatMap(character => s"$character$character"))
case 6 => Some(trimmedColorString)
case _ => None
}
val values: Option[Seq[Int]] = longColorString.map(_
.foldLeft(Seq[String]())((accu, character) => accu.lastOption.map(_.toSeq) match {
case Some(Seq(_, _)) => accu :+ s"$character" // previous value is complete => start with succeeding
case Some(Seq(c)) => accu.dropRight(1) :+ s"$c$character" // complete the previous value
case _ => Seq(s"$character") // start with an incomplete first value
})
.flatMap(hexString => scala.util.Try(Integer.parseInt(hexString, 16)).toOption)
// .flatMap(hexString => try {
// Some(Integer.parseInt(hexString, 16))
// } catch {
// case _: Exception => None
// })
)
values.flatMap(values => values.size match {
case 3 => Some((values.head, values(1), values(2)))
case _ => None
})
}
}
// example:
println(Color.stringToInts("#abc")) // prints Some((170,187,204))
You may run that example on https://scastie.scala-lang.org
The parts of that code I am most unsure about are
the match in the foldLeft (is it a good idea to use string interpolation or can the code be written shorter without string interpolation?)
Integer.parseInt in conjunction with try (can I use a prettier alternative in Scala?) (solved thanks to excellent comment by Xavier Guihot)
But I expect most parts of my code to be improvable. I do not want to introduce new libraries in addition to com.itextpdf to shorten my code, but using com.itextpdf functions is an option. (The result of stringToInts is going to be converted into a new com.itextpdf.kernel.colors.DeviceRgb(...), thus I have installed com.itextpdf anyway.)
Tests defining the expected function:
import org.scalatest.{BeforeAndAfterEach, FunSuite}
class ColorTest extends FunSuite with BeforeAndAfterEach {
test("shorthand mixed case color") {
val actual: Option[(Int, Int, Int)] = Color.stringToInts("#Fa#F")
val expected = (255, 170, 255)
assert(actual === Some(expected))
}
test("mixed case color") {
val actual: Option[(Int, Int, Int)] = Color.stringToInts("#1D9a06")
val expected = (29, 154, 6)
assert(actual === Some(expected))
}
test("too short long color") {
val actual: Option[(Int, Int, Int)] = Color.stringToInts("#1D9a6")
assert(actual === None)
}
test("too long shorthand color") {
val actual: Option[(Int, Int, Int)] = Color.stringToInts("#1D9a")
assert(actual === None)
}
test("invalid color") {
val actual: Option[(Int, Int, Int)] = Color.stringToInts("#1D9g06")
assert(actual === None)
}
}
At the moment of writing this answer the other answers don't properly handle rgb(), rgba() and named colors cases. Color strings that start with hashes (#) are only a part of the deal.
As you have iText7 as a dependency and iText7 has a pdfHTML add-on which means the logic for parsing CSS colors obviously must be somewhere in iText7 and, more importantly, it must handle various range of CSS color cases. The question is only about finding the right place. Fortunately, this API is public and easy to use.
The method you are interested in is WebColors.getRGBAColor() from package com.itextpdf.kernel.colors which accepts a CSS color string a returns a 4-element array with R, G, B, A values (last one stands for alpha, i.e. transparency).
You can use those values to create a color right away (code in Java):
float[] rgbaColor = WebColors.getRGBAColor("#ababab");
Color color = new DeviceRgb(rgbaColor[0], rgbaColor[1], rgbaColor[2]);
In Scala it must be something like
val rgbaColor = WebColors.getRGBAColor("#ababab");
val color = new DeviceRgb(rgbaColor(0), rgbaColor(1), rgbaColor(2));
I came up with this fun answer (untested); I guess the biggest help for you will be the use of sliding(2,2) instead of the foldLeft.
def stringToInts(colorString: String): Option[(Int, Int, Int)] = {
val trimmedString: String => String = _.trim.replaceAll("#", "")
val validString: String => Option[String] = s => s.length match {
case 3 => Some(s.flatMap(c => s"$c$c"))
case 6 => Some(s)
case _ => None
}
val hex2rgb: String => List[Option[Int]] = _.sliding(2, 2).toList
.map(hex => Try(Integer.parseInt(hex, 16)).toOption)
val listOpt2OptTriple: List[Option[Int]] => Option[(Int, Int, Int)] = {
case Some(r) :: Some(g) :: Some(b) :: Nil => Some(r, g, b)
case _ => None
}
for {
valid <- validString(trimmedString(colorString))
rgb = hex2rgb(valid)
answer <- listOpt2OptTriple(rgb)
} yield answer
}
Here is a possible implementation of your function
def stringToInts(css: String): Option[(Int, Int, Int)] = {
def cssColour(s: String): Int = {
val v = Integer.parseInt(s, 16)
if (s.length == 1) v*16 + v else v
}
val s = css.trim.replaceAll("#", "")
val l = s.length/3
if (l > 2 || l*3 != s.length) {
None
} else {
Try{
val res = s.grouped(l).map(cssColour).toSeq
(res(0), res(1), res(2))
}.toOption
}
}
The implementation would be cleaner if it returned Option[List[Int]] or even Try[List[Int]] to preserve the error in the case of failure.
If you're looking for conciseness, perhaps this solution will do the job (at the expense of efficiency—more on that later):
import scala.util.Try
def parseLongForm(rgb: String): Try[(Int, Int, Int)] =
Try {
rgb.replace("#", "").
grouped(2).toStream.filter(_.length == 2).
map(Integer.parseInt(_, 16)) match { case Stream(r, g, b) => (r, g, b) }
}
def parseShortForm(rgb: String): Try[(Int, Int, Int)] =
parseLongForm(rgb.flatMap(List.fill(2)(_)))
def parse(rgb: String): Option[(Int, Int, Int)] =
parseLongForm(rgb).orElse(parseShortForm(rgb)).toOption
In terms of conciseness is that every function here is effectively a one-liner (if that's something you're looking for right now).
The core is the function parseLongForm, which attempts to parse the long 6-character long form by:
removing the # character
grouping the characters in pairs
filtering out lone items (in case we have an odd number of characters)
parsing each pair
matching with the expected result to extract individual items
parseLongForm represents the possibility of failure with Try, which allows us to fail gracefully whenever parseInt or the pattern matching fails.
parse invokes parseLongForm and, if the result is a failure (orElse), invokes parseShortForm, which just tries the same approach after doubling each character.
It successfully passes the tests that you provided (kudos, that makes addressing the question much easier).
The main issue with this approach is that you would still try to parse the long form even if it can be clear from the beginning that it would not work. So, this is not recommended code if this could be a performance bottleneck for your use case. Another issue is that, although that's more or less hidden, we're using exceptions for flow control (which also hurts performance).
The nice things are conciseness and, I'd argue, readability (as I'd say that the code maps in a fairly straightforward fashion to the problem—but readability, of course, is by definition in the eye of the beholder).
You can find this solution on Scastie.

How do I pass in multiple parameters into a Ramda compose chain?

Here are four functions I am trying to compose into a single endpoint string:
const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const params = str => `${str}?sort=desc&part=true&`
const query = str => `${str}query={ some:'value', another:'value'}`
let finalEndpoint = R.compose(query, params, protocol, endpoint)
var result = finalEndpoint('api.content.io')
This composition works and returns the result I want which is:
https://api.content.io?sort=desc&part=true&query={ some:'value', another:'value'}
But notice how I have hard coded the values for params and query inside their function body. I see only one value going up the value in this R.compose chain.
How and where exactly do I pass in parameters to the params and query parameters?
UPDATE:
What I did was curried those functions like this:
var R = require('ramda');
const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const setParams = R.curry ( (str, params) => `${str}?${params}` )
const setQuery = R.curry ( (str, query) => `${str}&query=${JSON.stringify(query)}` )
and then
let finalEndpoint = R.compose(protocol, endpoint)
var result = setQuery(setParams(finalEndpoint('api.content.io'), 'sort=desc&part=true'), { some:'value', another:'value'})
console.log(result);
But the final call to get result still seems pretty hacked and inelegant. Is there any way to improve this?
How and where exactly do I pass in parameters to the params and query parameters?
Honestly, you don't, not when you're building a compose or pipe pipeline with Ramda or similar libraries.
Ramda (disclaimer: I'm one of the authors) allows the first function to receive multiple arguments -- some other libraries do, some don't -- but subsequent ones will only receive the result of the previous calls. There is one function in Sanctuary, meld, which might be helpful with this, but it does have a fairly complex API.
However, I don't really understand why you are building this function in this manner in the first place. Are those intermediate functions actually reusable, or are you building them on spec? The reason I ask is that this seems a more sensible version of the same idea:
const finalEndpoint = useWith(
(endpoint, params, query) =>`https://${endpoint}?${params}&query=${query}`, [
endpoint => endpoint || 'default',
pipe(toPairs, map(join('=')), join('&')),
pipe(JSON.stringify, encodeURIComponent)
]
);
finalEndpoint(
'api.content.io',
{sort: 'desc', part: true},
{some:'value', another:'value'}
);
//=> "https://api.content.io?sort=desc&part=true&query=%7B%22some%22%3A%22value%22%2C%22another%22%3A%22value%22%7D"
I don't really know your requirements for that last parameter. It looked strange to me without that encodeUriComponent, but perhaps you don't need it. And I also took liberties with the second parameter, assuming that you would prefer actual data in the API to a string encapsulating that data. But if you want to pass 'sort=desc&part=true', then replace pipe(toPairs, map(join('=')), join('&')) with identity.
Since the whole thing is far from points-free, I did not use a points-free version of the first function, perhaps or(__, 'default'), as I think what's there is more readable.
Update
You can see a version of this on the Ramda REPL, one that adds some console.log statements with tap.
This does raise an interesting question for Ramda. If those intermediate functions really are desirable, Ramda offers no way to combine them. Obviously Ramda could offer something like meld, but is there a middle ground? I'm wondering if there is a useful function (curried, of course) that we should include that works something like
someFunc([f0], [a0]); //=> f0(a0)
someFunc([f0, f1], [a0, a1]); //=> f1(f0(a0), a1)
someFunc([f0, f1, f2], [a0, a1, a2]); //=> f2(f1(f0(a0), a1), a2)
someFunc([f0, f1, f2, f3], [a0, a1, a2, a3]); //=> f3(f2(f1(f0(a0), a1), a2), a3)
// ...
There are some serious objections: What if the lists are of different lengths? Why is the initial call unary, and should we fix that by adding a separate accumulator parameter to the function? Nonetheless, this is an intriguing function, and I will probably raise it for discussion on the Ramda boards.
I wrote a little helper function for situations like this.
It is like compose, but with the rest params also passed in. The first param is the return value of the previous function. The rest params remain unchanged.
With it, you could rewrite your code as follows:
const compound = require('compound-util')
const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const params = (str, { params }) => `${str}?${params}`
const query = (str, { query }) => `${str}query=${query}`
const finalEndpoint = compound(query, params, protocol, endpoint)
const result = finalEndpoint('api.content.io', {
params: 'sort=desc&part=true&',
query: JSON.stringify({ some:'value', another:'value'})
})
If you have params and query as curried functions then you can:
EDIT: code with all the bells and whistles, needed to change parameter order or use R.__ and stringify object
const endpoint = R.curry( str => `${str}` || 'default' )
const protocol = R.curry( str => `https://${str}` )
const params = R.curry( (p, str) => `${str}?${p}` )
const query = R.curry( (q, str) => `${str}&query=${q}` )
let finalEndpoint =
R.compose(
query(JSON.stringify({ some:'value', another:'value' })),
params('sort=desc&part=true'),
protocol,
endpoint
)
var result = finalEndpoint('api.content.io')
console.log(result)

Filtering out maybe types before accessing nullable property

Given these two types:
type Point = [
number,
number,
];
type Some = {
a: Point,
b: ?Point,
};
And the data set:
const somes: Array<Some> = [
{a: [0, 1], b: [0, 2]},
{a: [2, 3], b: null}
]
Flow will automatically fail if we try to access somes[n].b.x given that b is a maybe type and might be either null or undefined.
We can however with confidence filter out all items in somes to exclude any item that does not include b:
const withB = somes.filter(s => !!s.b)
However flowtype will still complain when accessing items in withB as it doesn't pick up the exclusion:
console.log( withB.map(s => s.b[0]).join(',') )
// console.log(withB.map(s => s.b[0]).join(','))
// ^^^^^^ access of computed property/element. // Computed property/element cannot be accessed on possibly undefined value
// console.log(withB.map(s => s.b[0]).join(','))
// ^^^ undefined
Is it possible to somehow annotate or hint to flow that all items in withB are now guaranteed to include the b property?
Another option if you are willing to pay for additional computations
const withB = somes
.map(x => x.b ? { a: x.a, b: x.b } : null)
.filter(Boolean)
Here is the general way to hint Flow anything:
const withB: Array<{ a: Point, b: Point }> = (somes.filter(s => !!s.b): any)
It won't be safe in your case though. You have an array of mutable objects and property 'b' can be set to null at any time.

length of the longest possible string contains no repeated 3-mers

I'm trying to find the length of the longest possible string of consecutive digits that contains no repeated 3-mers.
This is a bioinformatics question, and I'm sorting this for protein sequence.
basically, something like 0102340109 does not work because 010repeats.
But something like 0002223589765 works because you cannot find any repeated 3 digits.
I need to find the longest sequence and I'm kinda stuck and clueless.
The following codes are written in ES6. You can make a sliding procedure which takes a string input a returns an Iterable of substring "windows"
Array.from(sliding (3,1) ('012345'))
// [ '012', '123', '234', '345' ]
Array.from(sliding (2,2) ('012345'))
// [ '01', '23', '45' ]
Array.from(sliding (4,2) ('012345'))
// [ '0123', '1234', '2345' ]
Then, using this, you can define a seqIsRepeated procedure which iterates thru the sliding windows. Instead of pre-computing the entire list of windows, we will look at them 1-by-1, adding each result to a Set. If the window already exists in the Set, true will be returned immediately and iteration is stopped. If the procedure makes it thru all windows without finding a duplicate, false will be returned.
const sliding = (m,n) => function* (xs) {
for (let i = 0; i + m <= xs.length; i += n)
yield xs.substr(i, m);
};
const seqIsRepeated = n => xs => {
let set = new Set();
for (let seq of sliding (n,1) (xs))
if (set.has(seq))
return true;
else
set.add(seq);
return false;
};
console.log (seqIsRepeated (3) ('0102340109')); // true
console.log (seqIsRepeated (3) ('0002223589765')); // false
This doesn't find you the longest sequence, but hopefully it does give you a start. From here, you'd be looking at substrings of your input sequence and using seqIsRepeated(3) to eliminate substrings as possibilities

Resources