Lean pass type as parameter - type-theory

I am trying to do some category theory in Lean. However, I am not yet very fluent in type theory, and the following does not really seem to work:
class pset (S: Type) :=
(point: S)
class category (𝒞: Type) :=
(test: unit)
instance pset_category : category pset :=
{
test := ()
}
I get a type mismatch at category pset, since pset has type Type -> Type, whereas it is expected to have type Type. What is going wrong?

I assume you want pset to be something like "pointed sets". So then its definition should be
class pset :=
(S : Type)
(point : S)
Now you will notice that #check pset tells you it has type Type 1. So you still can't make it into a category, since you only defined "small" categories. If you change Type to Type* in the definition of category, all should be good.

Related

What is the difference between F[A] and A?

For languages like Scala and Haskell, you can construct types using type constructors. What is the right vocabulary for differentiating between all of these parts?
A is a type. F[A] is also a type. Is there language that exists to differentiate the two?
What is A?
What is F[A]?
What is F?
Dunno about in Scala, but in Haskell, the Report does distinguish between two syntactic categories: "types" and "constructors". Constructors are just those types which are single atoms, beginning with an upper case letter, and created by data and newtype declarations. e.g.
data Foo a = Bar
creates a new type constructor Foo (and a new data constructor Bar), and types can be formed by applying Foo to another type. Of course, constructors need not be of higher kind; data Baz = Quux also declares a type constructor named Baz which is not permitted to be applied to any other types.
(But beware: it is common to use "type constructor" to mean "any type-level expression with an arrow kind", so if you are doing some technical writing, you should include some text in your introduction clarifying which of these two meanings you intend to use in the rest of the document.)
So, in your example, we could say Map is a constructor, Char is a constructor, Int is a constructor, Map Char is a type, and Map Char Int is a type.
As far as I know, there is no common shorthand term for any of these categories: "a type which is definitely not a constructor", "a type of kind *", "a type which is definitely not of kind *". For types which are allowed to be applied to another type, there is the term "higher-kinded type" -- e.g. Map and Map Char are both higher-kinded types.
I would propose to just call F[A] application of a type constructor F of kind * -> * to the argument A of kind *. "Type constructor" comes from the specification, whereas "application" comes from the basic lambda calculus, as explained below.
Recall that the formalism of higher-kinded types with all the type constructors is essentially just an extension of a simply typed lambda calculus over a single type *.
That means that you have the following rules for forming kinds:
* is a kind
if a, b are kinds, then a -> b is a kind
You can form terms as follows:
Predefined constants with fixed kind are terms
Variables are terms
If f and a are terms, then the application f a is a term
If x is a variable name, and y is a term, then the abstraction \x.y is a term
You can check whether a (type-valued) term is well-kinded with rules that look somewhat like this:
Predefined constant c of kind k (vacuously) has kind k, regardless of context
If context Gamma contains mapping of a variable v to kind k, then in Gamma we can infer that v is a well-kinded expression of kind k.
If in context Gamma we can infer that f has kind a -> b and x has kind a, then the application f x has kind b.
If in context Gamma, x: a we can infer that y has kind b, then in Gamma we can infer that \x.y has kind a -> b.
I don't see any reason to invent any new vocabulary, so I would just use "application".
An aside: you can actually write down the above basic kind-inference algorithm really quickly.
sealed trait Term
case class Apply(func: Term, arg: Term) extends Term
case class Lam(preferred: String, dom: Type, body: Term) extends Term
case class BoundVar(deBruijnIdx: Int) extends Term
case class FreeVar(name: String) extends Term
sealed trait Type
case object * extends Type
case class Func(dom: Type, cod: Type) extends Type {
override def toString = s"($dom -> $cod)"
}
import util.{Either, Left, Right}
case class Ctx(globalConstants: Map[String, Type], stack: List[Type]) {
def push(tp: Type): Ctx = Ctx(globalConstants, tp :: stack)
def pop: Ctx = Ctx(globalConstants, stack.tail)
}
object Ctx {
def empty = Ctx(Map.empty, List.empty)
def emptyWithGlobals(keys: (String, Type)*) = Ctx(keys.toMap, Nil)
}
def tinf(t: Term, ctx: Ctx = Ctx.empty): Either[String, Type] = t match {
case FreeVar(v) =>
ctx.globalConstants.get(v).map(Right(_)).getOrElse(Left("Undefined: " + v))
case BoundVar(d) => Right(ctx.stack(d))
case Apply(f, x) =>
for {
tf <- tinf(f, ctx)
tx <- tinf(x, ctx)
res <- tf match {
case Func(a, b) =>
if (tx == a) Right(b)
else Left(s"Type mismatch: cannot apply `$a` to `$b`")
case sthElse => Left(s"Not applicable: $sthElse")
}
} yield res
case Lam(_, tp, b) =>
for {
tb <- tinf(b, ctx.push(tp))
} yield Func(tp, tb)
}
for {
example <- List(
Lam("x", *, BoundVar(0)),
Lam("x", *, Lam("y", Func(*, *), Apply(BoundVar(0), BoundVar(1))))
)
} println(example + " : " + tinf(example))
and it will happily infer that type-lambdas
\(x:*).x
\(x:*).\y(* -> *). y x
have the kinds
(* -> *)
(* -> ((* -> *) -> *))
respectively.
The technical terms, as mentioned in the comments, are 'type', 'some other type', and a 'type constructor'.
Consider:
data A = A
-- ^ ^--- The Data Constructor
-- -- The type
data F x = SomeDataConstructorForF x
-- ^ ^ ^-- Data Constr ^-- Field
-- | --- Type Variable
-- - Type Constructor
val :: A
val = A
-- A value of type 'A'
val2 :: F [A]
val2 = SomeDataConstructorForF []
-- A value of some other type, F [A].
-- No special term exists for types built through application
-- of one or more type constructor afaik

How to understand the type name requirement for existential type?

From this question: Sample of `forSome { val `?
I learnt that, if I use this format of existential type:
type SomeList = List[v.T] forSome { val v : { type T }; }
There must be a type named T in the code.
But this code:
List[T] forSome { type T }
Although there is a { type T } as well, but it doesn't require a type named T exist, instead, it can match any type.
I can't understand why there is such difference, and can I expect the { type T } parts of two kinds have the exact same meaning?
OK, I'll have a try (though existential types are quite new to me too...)
Your first example uses a path-dependent type v.T, and means "given a value v containing a type called T, construct the type of List whose elements have type (v.T)".
Your second example
List[T] forSome { type T }
means "a list of type T where T could be any type", and is equivalent to:
List[_]
(The compiler actually gives the type as List[_] in Eclipse. David R. MacIver's article discusses this in more detail.)
so probably isn't very useful unless you add additional bounds to the type T
In the first example we are referring to a very specific named (path-dependent) type; In the answer to your linked question, T must exist and be bound to a concrete type, because we use it to access a value of that type:
object X {
type T = String
val x: T = "hello"
}
in the second example, we are referring to any type at all.
I think the different meaning of the same syntax is due to the different context (path-dependent type or plain type).
See also :
http://www.drmaciver.com/2008/03/existential-types-in-scala/
What is and when to use Scala's forSome keyword?
Lower type bound on Scala field in mutable, covariant class?

How to understand "The variance position of a method parameter is the opposite of the variance position of the enclosing parameter clause."

I see this sentence is scala specification (pdf):
The variance position of a method parameter is the opposite of the variance position of the enclosing parameter clause.
Which is on page 44.
But I can't quite understand it. Could you give me some samples?
So, let's start with a motivating example. Suppose I write the following:
class Foo[+A] {
def foo(a : A) = ???
}
Now, by annotating the type parameter A with a +, I've declared that Foo is covariant in A, which is to say that if X <: Y, then Foo[X] <: Foo[Y]. So, suppose I have such a Foo[X] and I try to pass it to a function which requires a Foo[Y]:
def bar(a : Y, x : Foo[Y]) = {
x.foo(a)
}
Now, bar tries to call x.foo with a Y. But x is a Foo[X], and X is a subtype of Y - so it's like trying to pass an Object to a function requiring a String - there's no guarantee that the Object contains everything that's needed to do this. So the definition of Foo above is invalid - to use the terminology in the specification, the type parameter A is covariant, but you've attempted to use it in a contravariant position - as the parameter to a function.
The set of rules set out in the Scala spec where you've referenced are the rules used by the Scala compiler to determine the variance position of different places in the code, which it uses to check that you haven't done anything like the definition of Foo above. The specific clause you identify gives the rule corresponding to the example above - it says that the variance position of a parameter clause (e.g. within the parameter list of a function) is the opposite of the surrounding variance position.
Usually, this means that parameter clauses are contravariant. However, things can get multiply inverted:
class Foo[A, B] {
def foo(a : A) = {
def bar(b : B) = ???
}
}
Here, the parameter clause of foo is contravariant, and hence the parameter clause of bar is inverted again, and is covariant. So the following definition is valid:
class Foo[-A, +B] {
def foo(a : A) = {
def bar(b : B) = ???
}
}

How do type classes work in Haskell?

I am really confused about classes in haskell. If I had the code:
class GetResult n where res :: n -> Int
class (GetResult n) => Model n where
starting :: Int -> [Int] -> n
starting i j = .....
test :: n -> n
test n = ......
What type is n? What type would starting output and test take as input?
Your confusion might be caused by the fact that type classes in Haskell have nothing to do with classes in OO. Most importantly type classes don't describe objects, they describe types.
A type class describes a set of methods. You can implement those methods for a given type to make that type an instance of the class. So your type class definition of GetResult can be read as "A type n can be made an instance of GetResult by implementing the method res of type n -> Int". So n is simply the type that wants to become an instance of GetResult.
As an example if you wanted to make Int an instance of GetResult, you could use the following instance declaration:
instance GetResult Int where
res :: Int -> Int
res i = i
In this case n would be Int.
n is a type variable, not any particular type. Particular types can be made instances of GetResult and Model, and each instance will "fill in the blanks" in the types of the functions defined in the class.
So the full type of starting is (you can get this from ghci with :t starting):
starting :: Model n => Int -> [Int] -> n
You can read this as "for any type which is an instance of Model, starting takes an Int and a [Int] and returns a value of that type". Likewise test takes any type which is an instance of Model and returns a value of the same type.
At any particular call of starting, the type returned will be determined by the context; it will return a value of whatever type its return value is used as in that context (assuming a suitable instance exists).

Impredicative types vs. plain old subtyping

A friend of mine posed a seemingly innocuous Scala language question last week that I didn't have a good answer to: whether there's an easy way to declare a collection of things belonging to some common typeclass. Of course there's no first-class notion of "typeclass" in Scala, so we have to think of this in terms of traits and context bounds (i.e. implicits).
Concretely, given some trait T[_] representing a typeclass, and types A, B and C, with corresponding implicits in scope T[A], T[B] and T[C], we want to declare something like a List[T[a] forAll { type a }], into which we can throw instances of A, B and C with impunity. This of course doesn't exist in Scala; a question last year discusses this in more depth.
The natural follow-up question is "how does Haskell do it?" Well, GHC in particular has a type system extension called impredicative polymorphism, described in the "Boxy Types" paper. In brief, given a typeclass T one can legally construct a list [forall a. T a => a]. Given a declaration of this form, the compiler does some dictionary-passing magic that lets us retain the typeclass instances corresponding to the types of each value in the list at runtime.
Thing is, "dictionary-passing magic" sounds a lot like "vtables." In an object-oriented language like Scala, subtyping is a much more simple, natural mechanism than the "Boxy Types" approach. If our A, B and C all extend trait T, then we can simply declare List[T] and be happy. Likewise, as Miles notes in a comment below, if they all extend traits T1, T2 and T3 then I can use List[T1 with T2 with T3] as an equivalent to the impredicative Haskell [forall a. (T1 a, T2 a, T3 a) => a].
However, the main, well-known disadvantage with subtyping compared to typeclasses is tight coupling: my A, B and C types have to have their T behavior baked in. Let's assume this is a major dealbreaker, and I can't use subtyping. So the middle ground in Scala is pimps^H^H^H^H^Himplicit conversions: given some A => T, B => T and C => T in implicit scope, I can again quite happily populate a List[T] with my A, B and C values...
... Until we want List[T1 with T2 with T3]. At that point, even if we have implicit conversions A => T1, A => T2 and A => T3, we can't put an A into the list. We could restructure our implicit conversions to literally provide A => T1 with T2 with T3, but I've never seen anybody do that before, and it seems like yet another form of tight coupling.
Okay, so my question finally is, I suppose, a combination of a couple questions that were previously asked here: "why avoid subtyping?" and "advantages of subtyping over typeclasses" ... is there some unifying theory that says impredicative polymorphism and subtype polymorphism are one and the same? Are implicit conversions somehow the secret love-child of the two? And can somebody articulate a good, clean pattern for expressing multiple bounds (as in the last example above) in Scala?
You're confusing impredicative types with existential types. Impredicative types allow you to put polymorphic values in a data structure, not arbitrary concrete ones. In other words [forall a. Num a => a] means that you have a list where each element works as any numeric type, so you can't put e.g. Int and Double in a list of type [forall a. Num a => a], but you can put something like 0 :: Num a => a in it. Impredicative types is not what you want here.
What you want is existential types, i.e. [exists a. Num a => a] (not real Haskell syntax), which says that each element is some unknown numeric type. To write this in Haskell, however, we need to introduce a wrapper data type:
data SomeNumber = forall a. Num a => SomeNumber a
Note the change from exists to forall. That's because we're describing the constructor. We can put any numeric type in, but then the type system "forgets" which type it was. Once we take it back out (by pattern matching), all we know is that it's some numeric type. What's happening under the hood, is that the SomeNumber type contains a hidden field which stores the type class dictionary (aka. vtable/implicit), which is why we need the wrapper type.
Now we can use the type [SomeNumber] for a list of arbitrary numbers, but we need to wrap each number on the way in, e.g. [SomeNumber (3.14 :: Double), SomeNumber (42 :: Int)]. The correct dictionary for each type is looked up and stored in the hidden field automatically at the point where we wrap each number.
The combination of existential types and type classes is in some ways similar to subtyping, since the main difference between type classes and interfaces is that with type classes the vtable travels separately from the objects, and existential types packages objects and vtables back together again.
However, unlike with traditional subtyping, you're not forced to pair them one to one, so we can write things like this which packages one vtable with two values of the same type.
data TwoNumbers = forall a. Num a => TwoNumbers a a
f :: TwoNumbers -> TwoNumbers
f (TwoNumbers x y) = TwoNumbers (x+y) (x*y)
list1 = map f [TwoNumbers (42 :: Int) 7, TwoNumbers (3.14 :: Double) 9]
-- ==> [TwoNumbers (49 :: Int) 294, TwoNumbers (12.14 :: Double) 28.26]
or even fancier things. Once we pattern match on the wrapper, we're back in the land of type classes. Although we don't know which type x and y are, we know that they're the same, and we have the correct dictionary available to perform numeric operations on them.
Everything above works similarly with multiple type classes. The compiler will simply generate hidden fields in the wrapper type for each vtable and bring them all into scope when we pattern match.
data SomeBoundedNumber = forall a. (Bounded a, Num a) => SBN a
g :: SomeBoundedNumber -> SomeBoundedNumber
g (SBN n) = SBN (maxBound - n)
list2 = map g [SBN (42 :: Int32), SBN (42 :: Int64)]
-- ==> [SBN (2147483605 :: Int32), SBN (9223372036854775765 :: Int64)]
As I'm very much a beginner when it comes to Scala, I'm not sure I can help with the final part of your question, but I hope this has at least cleared up some of the confusion and given you some ideas on how to proceed.
#hammar's answer is perfectly right. Here is the scala way of doint it. For the example i'll take Show as the type class and the values i and d to pack in a list :
// The type class
trait Show[A] {
def show(a : A) : String
}
// Syntactic sugar for Show
implicit final class ShowOps[A](val self : A)(implicit A : Show[A]) {
def show = A.show(self)
}
implicit val intShow = new Show[Int] {
def show(i : Int) = "Show of int " + i.toString
}
implicit val stringShow = new Show[String] {
def show(s : String) = "Show of String " + s
}
val i : Int = 5
val s : String = "abc"
What we want is to be able run the following code
val list = List(i, s)
for (e <- list) yield e.show
Building the list is easy but the list won't "remember" the exact type of each of its elements. Instead it will upcast each element to a common super type T. The more precise super super type between String and Int being Any, the type of the list is List[Any].
The problem is: what to forget and what to remember? We want to forget the exact type of the elements BUT we want to remember that they are all instances of Show. The following class does exactly that
abstract class Ex[TC[_]] {
type t
val value : t
implicit val instance : TC[t]
}
implicit def ex[TC[_], A](a : A)(implicit A : TC[A]) = new Ex[TC] {
type t = A
val value = a
val instance = A
}
This is an encoding of the existential :
val ex_i : Ex[Show] = ex[Show, Int](i)
val ex_s : Ex[Show] = ex[Show, String](s)
It pack a value with the corresponding type class instance.
Finally we can add an instance for Ex[Show]
implicit val exShow = new Show[Ex[Show]] {
def show(e : Ex[Show]) : String = {
import e._
e.value.show
}
}
The import e._ is required to bring the instance into scope. Thanks to the magic of implicits:
val list = List[Ex[Show]](i , s)
for (e <- list) yield e.show
which is very close to the expected code.