upward type inference vs downward type inference - type-inference

I am familiar to type inference.
var x = 5;
makes x to be of type int. But, what does upward type inference and downward type inference actually mean. Any help with simple example will be appreciated a lot.

Bottom-up (upward) inference is where the types of the constituent parts of an expression are known, and the type of the compound expression is inferred from that. Examples:
var x = 5; // `x` is inferred to be an integer.
var y = someString + someOtherString; ; // `y` is inferred to be a string.
// `list` is inferred to be an array/list of strings.
var list = ['foo', 'bar', 'baz'];
// If `someFunction` is generic, its type is determined from `x` and `y`.
someFunction(x, y);
Top-down (downward) inference is the opposite: the type of the compound expression is known, and the types of the constituent parts are inferred from them. Examples:
// `[]` is inferred to be a `List<int>`.
List<int> list = [];
// The type of `element` is inferred from the type of `list`, which in this
// case is `int`.
var squares = list.map((element) => element * element);
You should think of the direction in terms of an expression tree. For example:
operation
/ \
argument1 argument2
Inferring the types of the operation from its arguments would be bottom-up; inferring the types of the arguments from the operation would be top-down. (This is similar to bottom-up vs. top-down parsing.)

Related

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.

Generic transpose (or anything else really!) in Kotlin

Working on an Advent of Code puzzle I had found myself defining a function to transpose matrices of integers:
fun transpose(xs: Array<Array<Int>>): Array<Array<Int>> {
val cols = xs[0].size // 3
val rows = xs.size // 2
var ys = Array(cols) { Array(rows) { 0 } }
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
Turns out that in the following puzzle I also needed to transpose a matrix, but it wasn't a matrix of Ints, so i tried to generalize. In Haskell I would have had something of type
transpose :: [[a]] -> [[a]]
and to replicate that in Kotlin I tried the following:
fun transpose(xs: Array<Array<Any>>): Array<Array<Any>> {
val cols = xs[0].size
val rows = xs.size
var ys = Array(cols) { Array(rows) { Any() } } // maybe this is the problem?
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
This seems ok but it isn't. In fact, when I try calling it on the original matrix of integers I get Type mismatch: inferred type is Array<Array<Int>> but Array<Array<Any>> was expected.
The thing is, I don't really understand this error message: I thought Any was a supertype of anything else?
Googling around I thought I understood that I should use some sort of type constraint syntax (sorry, not sure it's called like that in Kotlin), thus changing the type to fun <T: Any> transpose(xs: Array<Array<T>>): Array<Array<T>>, but then at the return line I get Type mismatch: inferred type is Array<Array<Any>> but Array<Array<T>> was expected
So my question is, how do I write a transpose matrix that works on any 2-dimensional array?
As you pointed out yourself, the line Array(cols) { Array(rows) { Any() } } creates an Array<Array<Any>>, so if you use it in your generic function, you won't be able to return it when Array<Array<T>> is expected.
Instead, you should make use of this lambda to directly provide the correct value for the correct index (instead of initializing to arbitrary values and replacing all of them):
inline fun <reified T> transpose(xs: Array<Array<T>>): Array<Array<T>> {
val cols = xs[0].size
val rows = xs.size
return Array(cols) { j ->
Array(rows) { i ->
xs[i][j]
}
}
}
I don't really understand this error message: I thought Any was a supertype of anything else?
This is because arrays in Kotlin are invariant in their element type. If you don't know about generic variance, it's about describing how the hierarchy of a generic type compares to the hierarchy of their type arguments.
For example, assume you have a type Foo<T>. Now, the fact that Int is a subtype of Any doesn't necessarily imply that Foo<Int> is a subtype of Foo<Any>. You can look up the jargon, but essentially you have 3 possibilities here:
We say that Foo is covariant in its type argument T if Foo<Int> is a subtype of Foo<Any> (Foo types "vary the same way" as T)
We say that Foo is contravariant in its type argument T if Foo<Int> is a supertype of Foo<Any> (Foo types "vary the opposite way" compared to T)
We say that Foo is invariant in its type argument T if none of the above can be said
Arrays in Kotlin are invariant. Kotlin's read-only List, however, is covariant in the type of its elements. This is why it's ok to assign a List<Int> to a variable of type List<Any> in Kotlin.

How to make deeply nested function call polymorphic?

So I have a custom programming language, and in it I am doing some math formalization/modeling. In this instance I am doing basically this (a pseudo-javascript representation):
isIntersection([1, 2, 3], [1, 2], [2, 3]) // => true
isIntersection([1, 2, 3], [1, 2, 3], [3, 4, 5]) // => false
function isIntersection(setTest, setA, setB) {
i = 0
while (i < setTest.length) {
let t = setTest[i]
if (includes(setA, t) || includes(setB, t)) {
i++
} else {
return false
}
}
return true
}
function includes(set, element) {
for (x in set) {
if (isEqual(element, x)) {
return true
}
}
return false
}
function isEqual(a, b) {
if (a is Set && b is Set) {
return isSetEqual(a, b)
} else if (a is X... && b is X...) {
return isX...Equal(a, b)
} ... {
...
}
}
function isSetEqual(a, b) {
i = 0
while (i < a.length) {
let x = a[i]
let y = b[i]
if (!isEqual(x, y)) {
return false
}
i++
}
return true
}
The isIntersection is checking isEqual, and isEqual is configured to be able to handle all kinds of cases of equality check, from sets compared to sets, objects to objects, X's to X's, etc..
The question is, how can we make the isEqual somehow ignorant of the implementation details? Right now you have to have one big if/else/switch statement for every possible type of object. If we add a new type, we have to modify this gigantic isEqual method to add support for it. How can we avoid this, and just define them separately and cleanly?
I was thinking initially of making the objects be "instances of classes" so to speak, with class methods. But I like the purity of having everything just be functions and structs (objects without methods). Is there any way to implement this sort of thing without using classes with methods, instead keeping it just functions and objects?
If not, then how would you implement it with classes? Would it just be something like this?
class Set {
isEqual(set) {
i = 0
while (i < this.length) {
let x = this[i]
let y = set[i]
if (!x.isEqual(y)) {
return false
}
i++
}
return true
}
}
This would mean every object would have to have an isEqual defined on it. How does Haskell handle such a system? Basically looking for inspiration on how this can be most cleanly done. I want to ideally avoid having classes with methods.
Note: You can't just delegate to == native implementation (like assuming this is in JavaScript). We are using a custom programming language and are basically trying to define the meaning of == in the first place.
Another approach is to pass around an isEqual function along with everything somehow, though I don't really see how to do this and if it were possible it would be clunky. So not sure what the best approach is.
Haskell leverages its type and type-class system to deal with polymorphic equality.
The relevant code is
class Eq a where
(==) :: a -> a -> Bool
The English translation is: a type a implements the Eq class if, and only if, it defines a function (==) which takes two inputs of type a and outputs a Bool.
Generally, we declare certain "laws" that type-classes should abide by. For example, x == y should be identical to y == x in all cases, and x == x should never be False. There's no way for the compiler to check these laws, so one typically just writes them into the documentation.
Once we have defined the typeclass Eq in the above manner, we have access to the (==) function (which can be called using infix notation - ie, we can either write (==) x y or x == y). The type of this function is
(==) :: forall a . Eq a => a -> a -> Bool
In other words, for every a that implements the typeclass Eq, (==) is of type a -> a -> Bool.
Consider an example type
data Boring = Dull | Uninteresting
The type Boring has two proper values, Dull and Uninteresting. We can define the Eq implementation as follows:
instance Eq Boring where
Dull == Dull = True
Dull == Uninteresting = False
Uninteresting == Uninteresting = True
Uninteresting == Dull = False
Now, we will be able to evaluate whether two elements of type Boring are equal.
ghci> Dull == Dull
True
ghci> Dull == Uninteresting
False
Note that this is very different from Javascript's notion of equality. It's not possible to compare elements of different types using (==). For example,
ghci> Dull == 'w'
<interactive>:146:9: error:
* Couldn't match expected type `Boring' with actual type `Char'
* In the second argument of `(==)', namely 'w'
In the expression: Dull == 'w'
In an equation for `it': it = Dull == 'w'
When we try to compare Dull to the character 'w', we get a type error because Boring and Char are different types.
We can thus define
includes :: Eq a => [a] -> a -> Bool
includes [] _ = False
includes (x:xs) element = element == x || includes xs element
We read this definition as follows:
includes is a function that, for any type a which implements equality testing, takes a list of as and a single a and checks whether the element is in the list.
If the list is empty, then includes list element will evaluate to False.
If the list is not empty, we write the list as x : xs (a list with the first element as x and the remaining elements as xs). Then x:xs includes element iff either x equals element, or xs includes element.
We can also define
instance Eq a => Eq [a] where
[] == [] = True
[] == (_:_) = False
(_:_) == [] = False
(x:xs) == (y:ys) = x == y && xs == ys
The English translation of this code is:
Consider any type a such that a implements the Eq class (in other words, so that (==) is defined for type a). Then [a] also implements the Eq type class - that is, we can use (==) on two values of type [a].
The way that [a] implements the typeclass is as follows:
The empty list equals itself.
An empty list does not equal a non-empty list.
To decide whether two non-empty lists (x:xs) and (y:ys) are equal, check whether their first elements are equal (aka whether x == y). If the first elements are equal, check whether the remaining elements are equal (whether xs == ys) recursively. If both of these are true, the two lists are equal. Otherwise, they're not equal.
Notice that we're actually using two different ==s in the implementation of Eq [a]. The equality x == y is using the Eq a instance, while the equality xs == ys is recursively using the Eq [a] instance.
In practice, defining Eq instances is typically so simple that Haskell lets the compiler do the work. For example, if we had instead written
data Boring = Dull | Uninteresting deriving (Eq)
Haskell would have automatically generated the Eq Boring instance for us. Haskell also lets us derive other type classes like Ord (where the functions (<) and (>) are defined), show (which allows us to turn our data into Strings), and read (which allows us to turn Strings back into our data type).
Keep in mind that this approach relies heavily on static types and type-checking. Haskell makes sure that we only ever use the (==) function when comparing elements of the same type. The compiler also always knows at compile type which definition of (==) to use in any given situation because it knows the types of the values being compared, so there is no need to do any sort of dynamic dispatch (although there are situations where the compiler will choose to do dynamic dispatch).
If your language uses dynamic typing, this method will not work and you'll be forced to use dynamic dispatch of some variety if you want to be able to define new types. If you use static typing, you should definitely look into Haskell's type class system.

Chaining iterators of different types

I get type errors when chaining different types of Iterator.
let s = Some(10);
let v = (1..5).chain(s.iter())
.collect::<Vec<_>>();
Output:
<anon>:23:20: 23:35 error: type mismatch resolving `<core::option::Iter<'_, _> as core::iter::IntoIterator>::Item == _`:
expected &-ptr,
found integral variable [E0271]
<anon>:23 let v = (1..5).chain(s.iter())
^~~~~~~~~~~~~~~
<anon>:23:20: 23:35 help: see the detailed explanation for E0271
<anon>:24:14: 24:33 error: no method named `collect` found for type `core::iter::Chain<core::ops::Range<_>, core::option::Iter<'_, _>>` in the current scope
<anon>:24 .collect::<Vec<_>>();
^~~~~~~~~~~~~~~~~~~
<anon>:24:14: 24:33 note: the method `collect` exists but the following trait bounds were not satisfied: `core::iter::Chain<core::ops::Range<_>, core::option::Iter<'_, _>> : core::iter::Iterator`
error: aborting due to 2 previous errors
But it works fine when zipping:
let s = Some(10);
let v = (1..5).zip(s.iter())
.collect::<Vec<_>>();
Output:
[(1, 10)]
Why is Rust able to infer the correct types for zip but not for chain and how can I fix it? n.b. I want to be able to do this for any iterator, so I don't want a solution that just works for Range and Option.
First, note that the iterators yield different types. I've added an explicit u8 to the numbers to make the types more obvious:
fn main() {
let s = Some(10u8);
let r = (1..5u8);
let () = s.iter().next(); // Option<&u8>
let () = r.next(); // Option<u8>
}
When you chain two iterators, both iterators must yield the same type. This makes sense as the iterator cannot "switch" what type it outputs when it gets to the end of one and begins on the second:
fn chain<U>(self, other: U) -> Chain<Self, U::IntoIter>
where U: IntoIterator<Item=Self::Item>
// ^~~~~~~~~~~~~~~ This means the types must match
So why does zip work? Because it doesn't have that restriction:
fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
where U: IntoIterator
// ^~~~ Nothing here!
This is because zip returns a tuple with one value from each iterator; a new type, distinct from either source iterator's type. One iterator could be an integral type and the other could return your own custom type for all zip cares.
Why is Rust able to infer the correct types for zip but not for chain
There is no type inference happening here; that's a different thing. This is just plain-old type mismatching.
and how can I fix it?
In this case, your inner iterator yields a reference to an integer, a Clone-able type, so you can use cloned to make a new iterator that clones each value and then both iterators would have the same type:
fn main() {
let s = Some(10);
let v: Vec<_> = (1..5).chain(s.iter().cloned()).collect();
}
If you are done with the option, you can also use a consuming iterator with into_iter:
fn main() {
let s = Some(10);
let v: Vec<_> = (1..5).chain(s.into_iter()).collect();
}

Is g++ 4.5.3 broken when it comes to pointers to lamba functions?

I was trying out lambda functions and making a jump table to execute them, but I found g++ didn't recognize the type of the lambda function such that I could assign them to an array or tuple container.
One such attempt was this:
auto x = [](){};
decltype(x) fn = [](){};
decltype(x) jmpTable[] = { [](){}, [](){} };
On compilation I get these errors:
tst.cpp:53:27: error: conversion from ‘main()::<lambda()>’ to non-scalar type ‘main()::<lambda()>’ requested
tst.cpp:54:39: error: conversion from ‘main()::<lambda()>’ to non-scalar type ‘main()::<lambda()>’ requested
Hmmmm, can't convert from type A to non-scalar type A? What's that mean? o.O
I can use std::function to get this to work, but a problem with that is it doesn't seem to work with tuple:
function<void()> jmpTable[] = [](){}; // works
struct { int i; function<void()>> fn; } myTuple = {1, [](){}}; // works
tuple<int, function<void()>> stdTuple1 = {1, [](){}}; // fails
tuple<int, function<void()>> stdTuple2 = make_tuple(1, [](){}); // works
tst.cpp:43:58: error: converting to ‘std::tuple<int, std::function<void()> >’ from initializer list would use explicit constructor ‘std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&) [with _U1 = int, _U2 = main()::<lambda()>, _T1 = int, _T2 = std::function<void()>]’
Constructor marked explicit? Why?
So my question is if I am doing something invalid or is this version just not quite up to the task?
Hmmmm, can't convert from type A to non-scalar type A? What's that mean? o.O
No, that's not a conversion to the same type. Despite having identical bodies, the different lambdas have different types. Newer versions of GCC make this clearer, and give the error message:
error: conversion from '__lambda1' to non-scalar type '__lambda0' requested
clang does even better:
error: no viable conversion from '<lambda at test.cc:2:18>' to 'decltype(x)' (aka '<lambda at test.cc:1:10>')
I can use std::function to get this to work, but a problem with that is it doesn't seem to work with tuple:
It does (with 4.5.4, at least, I don't have 4.5.3 to test), but your initialisation isn't quite right.
tuple<int, function<void()>> stdTuple1 {1, [](){}}; // lose the = to initialise stdTuple1 directly
I'm not sure about the state of n3043 in 4.5.3, but you should be able to use function pointer conversion. If I'm not misunderstanding your usage intentions, this may work for you;
void (*x)();
decltype(x) fn = [](){};
decltype(x) jmpTable[] = { [](){}, [](){} };