Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define type lambda properly?

I used =:= as example type lambda for purpose of making simple minimal example.

=:= type take two arguments, I'd like to curry one at type level.

I take naive implementation type Curry[G] = {type l[L] = L =:= G} but in practical uses it causes errors:

type X = Int
type Y = Int

type CurryInt[T] = T =:= Int
type Curry[G] = {type l[L] = L =:= G}
type CurrStatic = {type l[L] = L =:= Int}
object CurryObj {type l[L] = L =:= Int}

trait Apply[P[_], T]
implicit def liftApply[P[_], T](implicit ev : P[T]) = new Apply[P,T] {}

implicitly[Apply[CurryInt, Y]] // ok
implicitly[Apply[Curry[X]#l, Y]] // fails
implicitly[Apply[Curry[X]#l, Y]](liftApply) // fails
implicitly[Apply[Curry[X]#l, Y]](liftApply[Curry[X]#l, Y]) // ok
implicitly[Apply[CurrStatic#l, Y]] // fails
implicitly[Apply[CurryObj.l, Y]] // ok

Type inference breaks here. How should I define type lambdas to make it work?

like image 576
ayvango Avatar asked Aug 11 '17 20:08

ayvango


People also ask

How do you type a lambda function?

Lambda uppercase and lowercase symbol codesUse the Alt + X shortcut in Word for Windows, for example type 039B then Alt + X to enter Λ. Or enter the value into Character Code fields in Symbol dialog boxes to jump to that symbol.

How do you define a lambda function?

In Python, a lambda function is a single-line function declared with no name, which can have any number of arguments, but it can only have one expression. Such a function is capable of behaving similarly to a regular function declared using the Python's def keyword.

What is the datatype of a lambda?

The lambda expressions have a very simple, precise syntax and provide flexibility to specify the datatypes for the function parameters. Its return type is a parameter -> expression body to understand the syntax, we can divide it into three parts.


2 Answers

Consider this simplified version of your example:

trait Secret
type Curry = { type l[L] = Secret }

def foo[P[_], T](ev : P[T]) = ???
val bar: Curry#l[Int] = ???

foo(bar)

When calling foo the value bar is simply of type Secret, the compiler doesn't know from where your particular Secret comes from.

Your bar value is just a Secret, and it doesn't maintain information pointing back to Curry#l[Int].

The compiler cannot infer that P => Curry#l and T => Int.

The compiler only sees the Secret and loses the Curry#l context despite annotating the type with Curry#l[Int] instead of Secret.

Another example (coming from this question), exposing a similar behaviour:

trait Curry { type l }
trait CurryB extends Curry { type l = String }

def foo[P <: Curry](x: P#l) = ???
val bar: CurryB#l = ???

foo(bar)

CurryObj situation is different, consider that CurryInt#l, Curry#l, and CurrStatic#l are just type aliases. CurryObj.l, instead, is an actual type, part of the concrete object CurryObj.

Let's have a look to this (REPL):

scala> trait Secret
defined trait Secret

scala> type Curry = { type l[L] = Secret }
defined type alias Curry

scala> object CurryObj { type l[L] = Secret }
defined object CurryObj

scala> object S extends Secret
defined object S

scala> val foo0: Curry#l[Int] = S
foo0: Secret = S$@2c010477

scala> val foo1: CurryObj.l[Int] = S
foo1: CurryObj.l[Int] = S$@2c010477

Note that the type alias Curry#l[Int] -> Secret is resolved immediately, instead the actual type CurryObj.l[Int] is kept.

like image 141
Federico Pellegatta Avatar answered Sep 17 '22 17:09

Federico Pellegatta


slightly more verbose, but compiles :) (scala 2.12.3)

  type X = Int
  type Y = Int

  type CurryInt[T] = T =:= Int
  type Curry[G] = {type l[L] = =:=[L, G]}
  type CurrStatic = {type l[L] = L =:= Int}
  object CurryObj {type l[L] = L =:= Int}

  trait Apply[P[_], T]
  implicit def liftApply[P[_], T](implicit ev : P[T]) = new Apply[P,T] {}


  type L1[R] = =:=[R, X]
  type L2[R] = =:=[R, Int]
  implicitly[Apply[CurryInt, Y]] // ok
  implicitly[Apply[L1, Y]] // ok
  implicitly[Apply[L1, Y]](liftApply[L1, Y]) // ok
  implicitly[Apply[Curry[X]#l, Y]](liftApply[Curry[X]#l, Y]) // ok
  implicitly[Apply[L2, Y]] // ok
  implicitly[Apply[CurryObj.l, Y]] // ok
like image 33
pedromss Avatar answered Sep 19 '22 17:09

pedromss