How do I type lodash/fp curried functions? - lodash

I'm trying to add to the flow-typed typings. I'm starting with the lodash/fp module because that is most useful to myself. However, I'm struggling with how to type it correctly.
A simple example if dropRightWhile:
declare function dropRightWhile<T>(iteratee: (val: T)=>boolean, data?: Array<T>): Array<T> | (data: Array<T>)=>Array<T>;
This is my attempt to type it. dropRightWhile must take an iteratee, and it could take the data. If you don't give it data then it returns a function that takes the data, but if you give it data then it returns an array.
The type I have made doesn't strictly make the connection between number of arguments and return type. However, when I try to use a curried dropRightWhile I get an error
var c = dropRightWhile((x) => x> 0); c([0, 1, 2, 3]);
error: Function cannot be called on array type
I would've thought that since dropRightWhile can return a function then I would be able to call it, but it seems the array type is getting in the way.
Any suggestions?

You can define 2 overloadings
declare function dropRightWhile<T>(iteratee: (val : T) => boolean, data : Array<T>) : Array<T>;
declare function dropRightWhile<T>(iteratee: (val : T) => boolean): (data : Array<T>) => Array<T>;
// tests
const iteratee = x => x > 0;
(dropRightWhile(iteratee)([0, 1, 2, 3]) : Array<number>);
(dropRightWhile(iteratee, [0, 1, 2, 3]) : Array<number>)

Related

Ramda pick for fp-ts options / maybe

Using fp-ts. I have an option of an array
const arrayofKeys: Option<Array<K>>,
and an option of a record
const record: Option<Record<K,V>>
I want to pick the Vs of the Record where Ks intersect with the Array and stick the result in an Option.
In ramda: R.pick(arrayOfKeys, record)
How do i solve this with fp-ts or other packages within the fp-ts ecosystem?
I'd personally avoid Ramda et al as in my experience they're not very well typed. Here's a pure fp-ts approach (Str.fromNumber is from fp-ts-std, trivially replaced):
declare const arrayOfKeyNums: Option<Array<number>>
const arrayOfKeys = pipe(arrayOfKeyNums, O.map(A.map(Str.fromNumber)))
declare const record: Option<Record<string, number>>
const keyIntersectedVals: O.Option<Array<number>> = pipe(
sequenceT(O.Apply)(arrayOfKeys, record),
O.map(([ks, rec]) =>
pipe(
rec,
R.foldMapWithIndex(Str.Ord)(A.getMonoid<number>())((k, v) =>
A.elem(Str.Eq)(k)(ks) ? [v] : [],
),
),
),
)
It's a bit verbose owing to the need to pass typeclass instances around. On the plus side, the use of typeclass instances means that this can be trivially updated to support any value type, including non-primitive types with any given Eq.
Here's what the body might instead look like in Haskell for comparison, where typeclass instances don't need to be passed around:
keyIntersectedVals :: Maybe [Int]
keyIntersectedVals = uncurry (M.foldMapWithKey . intersectedToList) <$> sequenceT (mkeys, mmap)
where intersectedToList ks k v
| k `elem` ks = [v]
| otherwise = []
For example, given keys O.some(["a", "c"]) and a record O.some({ a: 123, b: 456, c: 789 }), we get O.some([123, 789]).
Ramda's lift lifts a function on some values to work on a container of those values. So lift (pick) will likely do what you want, so long as fp-ts's Option supports the FantasyLand Apply specification.
const {of} = folktale.maybe
const {lift, pick} = R
const keys = of (['k', 'e', 'y', 's']) // Maybe (['k', 'e', 'y', 's'])
const record = of ({s: 1, k: 2, y: 3, b: 4, l: 5, u: 6, e: 7}) // Maybe ({s: 1, k: 2, ...})
console .log (lift (pick) (keys, record) .toString())
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/folktale/2.0.0/folktale.min.js"></script>
This is a great use case for traverseArray, an optimized version of traverse. You can also use "Do notation" and apS to get a really clean, monadic pipeline. If any of these operations return a None, the entire flow will terminate early (this is a good!).
Also, lookup is a very handy function similar to get from Ramda/Lodash, but it returns an Option. Both the Record and Array modules export a version of this function.
declare const arrayofKeys: O.Option<Array<string>>
declare const record: O.Option<Record<string, number>>
export const result: O.Option<ReadonlyArray<number>> = pipe(
O.Do,
O.apS('keys', arrayofKeys),
O.apS('rec', record),
O.chain(({ keys, rec }) =>
pipe(
keys,
O.traverseArray(key => pipe(rec, R.lookup(key)))
)
)
)
Functions used:
https://gcanti.github.io/fp-ts/modules/Option.ts.html#do
https://gcanti.github.io/fp-ts/modules/Option.ts.html#aps
https://gcanti.github.io/fp-ts/modules/Option.ts.html#chain
https://gcanti.github.io/fp-ts/modules/Option.ts.html#traversearray
https://gcanti.github.io/fp-ts/modules/Record.ts.html#lookup

Implementing map & min that takes the tables.keys iterator as argument in Nim

I would like to define overloads of map and min/max (as originally defined in sequtils) that works for tables.keys. Specifically, I want to be able to write something like the following:
import sequtils, sugar, tables
# A mapping from coordinates (x, y) to values.
var locations = initTable[(int, int), int]()
# Put in some random values.
locations[(1, 2)] = 1
locations[(2, 1)] = 2
locations[(-2, 5)] = 3
# Get the minimum X coordinate.
let minX = locations.keys.map(xy => xy[0]).min
echo minX
Now this fails with:
/usercode/in.nim(12, 24) Error: type mismatch: got <iterable[lent (int, int)], proc (xy: GenericParam): untyped>
but expected one of:
proc map[T, S](s: openArray[T]; op: proc (x: T): S {.closure.}): seq[S]
first type mismatch at position: 1
required type for s: openArray[T]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
expression: map(keys(locations), proc (xy: auto): auto = xy[0])
Below are my three attempts at writing a map that works (code on Nim playground: https://play.nim-lang.org/#ix=3Heq). Attempts 1 & 2 failed and attempt 3 succeeded. Similarly, I implemented min using both attempt 1 & attempt 2, and attempt 1 failed while attempt 2 succeeded.
However, I'm confused as to why the previous attempts fail, and what the best practice is:
Why does attempt 1 fail when the actual return type of the iterators is iterable[T]?
Why does attempt 2 fail for tables.keys? Is tables.keys implemented differently?
Is attempt 2 the canonical way of taking iterators / iterables as function arguments? Are there alternatives to this?
Attempt 1: Function that takes an iterable[T].
Since the Nim manual seems to imply that the result type of calling an iterator is iterable[T], I tried defining map for iterable[T] like this:
iterator map[A, B](iter: iterable[A], fn: A -> B): B =
for x in iter:
yield fn(x)
But it failed with a pretty long and confusing message:
/usercode/in.nim(16, 24) template/generic instantiation of `map` from here
/usercode/in.nim(11, 12) Error: type mismatch: got <iterable[(int, int)]>
but expected one of:
iterator items(a: cstring): char
first type mismatch at position: 1
required type for a: cstring
but expression 'iter' is of type: iterable[(int, int)]
... (more output like this)
From my understanding it seems to say that items is not defined for iterable[T], which seems weird to me because I think items is exactly what's need for an object to be iterable?
Attempt 2: Function that returns an iterator.
I basically copied the implementation in def-/nim-itertools and defined a map function that takes an iterator and returns a new closure iterator:
type Iterable[T] = (iterator: T)
func map[A, B](iter: Iterable[A], fn: A -> B): iterator: B =
(iterator: B =
for x in iter():
yield fn(x))
but this failed with:
/usercode/in.nim(25, 24) Error: type mismatch: got <iterable[lent (int, int)], proc (xy: GenericParam): untyped>
but expected one of:
func map[A, B](iter: Iterable[A]; fn: A -> B): B
first type mismatch at position: 1
required type for iter: Iterable[map.A]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
proc map[T, S](s: openArray[T]; op: proc (x: T): S {.closure.}): seq[S]
first type mismatch at position: 1
required type for s: openArray[T]
but expression 'keys(locations)' is of type: iterable[lent (int, int)]
expression: map(keys(locations), proc (xy: auto): auto = xy[0])
which hints that maybe tables.keys doesn't return an iterator?
Attempt 3: Rewrite keys using attempt 2.
This replaces tables.keys using a custom myKeys that's implemented in a similar fashion to the version of map in attempt 2. Combined with map in attempt 2, this works:
func myKeys[K, V](table: Table[K, V]): iterator: K =
(iterator: K =
for x in table.keys:
yield x)
Explanation of errors in first attempts
which hints that maybe tables.keys doesn't return an iterator
You are right. It does not return an iterator, it is an iterator that returns elements of the type of your Table keys. Unlike in python3, there seems to be no difference between type(locations.keys) and type(locations.keys()). They both return (int, int).
Here is keys prototype:
iterator keys[A, B](t: Table[A, B]): lent A
The lent keyword avoids copies from the Table elements.
Hence you get a type mismatch for your first and second attempt:
locations.keys.map(xy => xy[0]) has an incorrect first parameter, since you get a (int, int) element where you expect a iterable[A].
Proposals
As for a solution, you can either first convert your keys to a sequence (which is heavy), like hola suggested.
You can directly rewrite a procedure for your specific application, mixing both the copy in the sequence and your operation, gaining a bit in performance.
import tables
# A mapping from coordinates (x, y) to values.
var locations = initTable[(int, int), int]()
# Put in some random values.
locations[(1, 2)] = 1
locations[(2, 1)] = 2
locations[(-2, 5)] = 3
func firstCoordinate[X, Y, V](table: Table[(X, Y), V]): seq[X] =
result = #[]
for x in table.keys:
result.add(x[0])
let minX = locations.firstCoordinate.min
echo minX
This is not strictly adhering your API, but should be more efficient.

Initializing a list in kotlin

I am trying to initlaise a list as part of a constructor argument. But I do not understand what it wants from me
distortion = List(
size = 10,
init = 0
)
The list is of type room entity
var distortion: List<DistortionCacheEntity>? = null
The init part is underlined in red. I dont know what to put in there or how to write it. Could someone help.
The function you are trying to invoke looks like this:
public inline fun <T> List(size: Int, init: (index: Int) -> T): List<T>
So init here is not an Integer but rather a function. Invoke like so:
distortion = List(size = 10) { index : Int ->
//Create object that the list needs to hold
}
var distortion: List<DistortionCacheEntity>? = null
distortion = List(10) { index -> DistortionCacheEntity()}
The simplest way to initialize a list is with kotlin library function listOf(...)
For example,
listOf(1, 2, 3) // [1, 2, 3]

dataframe-go: How to filter using < > operators?

I'm trying to do a simple filter in dataframe-go. I adapted from the Github example and tried to use a simple > operator in the Filter Function, but the compiler gave invalid operation: vals["day"] > 4 (operator > not defined on interface) error (see my code below)
Ok, so I changed the type to map[string]int64 but then, it gave the error: cannot convert func literal (type func(map[string]int64, int, int) (dataframe.FilterAction, error)) to type dataframe.FilterDataFrameFn.
I'm very familiar with R DataFrame/Table and Pandas but dataframe-go's API is rather convoluted. The only web resource I found is this but the author also stated he couldn't understand the filter API.
Any help is appreciated, thanks!
s1 := dataframe.NewSeriesInt64("day", nil, 1, 2, 3, 4, 5, 6, 7, 8)
s2 := dataframe.NewSeriesFloat64("sales", nil, 50.3, 23.4, 56.2, nil, nil, 84.2, 72, 89)
df := dataframe.NewDataFrame(s1, s2)
// Try filtering
filterFn := dataframe.FilterDataFrameFn(
func(vals map[string]int64, row, nRows int) (dataframe.FilterAction, error) {
//func(vals map[interface{}]interface{}, row, nRows int) (dataframe.FilterAction, error) {
if vals["day"] > 4 { // <= This is where I changed things
return dataframe.KEEP, nil
}
return dataframe.DROP, nil
})
ctx := context.Background()
dt_filtered, _ := dataframe.Filter(ctx, df, filterFn)
fmt.Print(dt_filtered)
You have to pass a function with the required signature, so vals must be a map[interface{}]interface{}. This is required because Go is not an interpreted language, and the code calling that function you passed as an argument has no compile-time knowledge of the function passed in.
Since your values are interface{}s, you have to convert them to the correct type to operate with them:
if ivalue, ok:=vals["day"].(int64); ok { // Check if the value is int64, and go ahead if so
if ivalue > 4 {
return dataframe.KEEP, nil
}
}

Should there be an indicesWhere method on Scala's List class?

Scala's List classes have indexWhere methods, which return a single index for a List element which matches the supplied predicate (or -1 if none exists).
I recently found myself wanting to gather all indices in a List which matched a given predicate, and found myself writing an expression like:
list.zipWithIndex.filter({case (elem, _) => p(elem)}).map({case (_, index) => index})
where p here is some predicate function for selecting matching elements. This seems a bit of an unwieldy expression for such a simple requirement (but I may be missing a trick or two).
I was half expecting to find an indicesWhere function on List which would allow me to write instead:
list.indicesWhere(p)
Should something like this be part of the Scala's List API, or is there a much simpler expression than what I've shown above for doing the same thing?
Well, here's a shorter expression that removes some of the syntactic noise you have in yours (modified to use Travis's suggestion):
list.zipWithIndex.collect { case (x, i) if p(x) => i }
Or alternatively:
for ((x,i) <- list.zipWithIndex if p(x)) yield i
But if you use this frequently, you should just add it as an implicit method:
class EnrichedWithIndicesWhere[T, CC[X] <: Seq[X]](xs: CC[T]) {
def indicesWhere(p: T => Boolean)(implicit bf: CanBuildFrom[CC[T], Int, CC[Int]]): CC[Int] = {
val b = bf()
for ((x, i) <- xs.zipWithIndex if p(x)) b += i
b.result
}
}
implicit def enrichWithIndicesWhere[T, CC[X] <: Seq[X]](xs: CC[T]) = new EnrichedWithIndicesWhere(xs)
val list = List(1, 2, 3, 4, 5)
def p(i: Int) = i % 2 == 1
list.indicesWhere(p) // List(0, 2, 4)
You could use unzip to replace the map:
list.zipWithIndex.filter({case (elem, _) => p(elem)}).unzip._2