New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added a :kind command to the REPL #2340
Conversation
I probably have to somehow assign this pull request to @paulp, but it looks like I don't have permissions to do that. |
Two things to address before we can consider this:
Oh, and happy Easter, too! 🐰 |
Using Scala syntax does add the ability to show variance and bounds and we might even get it for free from simply displaying the signature from Anonymizing them both as |
@folone For the majority of Scala users (assuming without any Haskell background)
|
For the test, I was going to suggest overriding toString; but I don't know if that was an extraneous part of the test. |
I agree it would be preferable to have a form that is something that we can use in Scala code. |
PLS REBUILD ALL |
(kitty-note-to-self: ignore 15697719) |
Created
|
I'm not really sure what makes the most sense. Just to add a bit more confusion:
|
For any which go deeper than a single type constructor, how about something like this - I probably blew the logic since I'm jumping on a plane, but wave your hands and make it right, you get the gist.
I like this less than what I pictured when I started it, but I think some sort of decomposition is unavoidable. |
Unapply show down. standard notation
Eugene's Scala notationY[X[F[A1]], A2] REPL's current notation for eta-expanded type constructor[TC[_[_]], MA]Unapply[TC,MA] Paul's notationI'm interpreting Paul's suggestion to be "Use function-like syntax to express type constructor": [_1, MA] => Unapply[_1, MA]
where _1 = [_2] => X[_2]
where _2 = [A1] => F[A1] why mine is betterIf you put scala> trait Foo[Y[X[F[A1]], A2]]
warning: there were 3 feature warning(s); re-run with -feature for details
defined trait Foo Using The naming issue. Let's step back and ask the type of
Yea, REPL gives
Keeping the original type variable names coud be confusing too. Some people use
|
👍 I like @eed3si9n's notation. We could also consider adding other notation(s) to the verbose output. Something like: scala> :k Unapply
Unapply's kind is Y[X[F[A1]], A2]
scala> :k -v Unapply
Unapply's kind is Y[X[F[A1]], A2]
In standard kind notation: ((* -> *) -> *) -> * -> *
In decomposed notation:
[_1, MA] => Unapply[_1, MA]
where _1 = [_2] => X[_2]
where _2 = [A1] => F[A1]
This is a type constructor that takes type constructor(s): a higher-kinded type. |
For completeness, I should point out that kinds also track bounds and variance, as discussed in http://adriaanm.github.com/files/higher.pdf |
Adriaan's comment is part of why I was devising my plane-aborted expanded notation. If we're seeking a "scala syntax" it must be capable of expressing type constructor variance and bounds, which means a bunch of stars won't suffice, and underscores will only take you so far. |
@paulp Isn't "Scala syntax" essentially the same as the type parameter expression we write between the braces? trait Foo[F[A <: Ordered[A]] <: Iterable[A]]
trait Foo[F[+A]] |
The problems arise at the boundaries. I assume we're all familiar with the problem in this one:
The collision between an existential and a "don't care" placeholder type argument reaches tragic proportions if we'd like to come anywhere near optimal syntax for expressing kinds. Even this can mean two different things
You have to know whether Foo's type argument is * -> * or * in order to know what F is doing there. But if the point of it is to communicate Foo's kind... I think we tolerate an unacceptable level of syntactic ambiguity. |
package interpreter | ||
|
||
trait Kind { | ||
type T <: scala.reflect.api.Universe |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are conventions to which we should attempt to adhere. This T should be called either U (for Universe) or G (for Global.)
Since we're discussing implementation, we have a loose consensus on attempting Scala syntax as kind notation? If so could we roll back the last commit "Addressed some of issues, raised by @paulp" and merge folone/scala: folone/scala@ca9edc1 from @folone I'd also like to get a chance to review the review before incorporating it. |
@eed3si9n sure, go ahead. I actually should have done this in another branch. |
That would be the ideal outcome of my manipulative reference to that old branch. |
@paulp I guess if I had the full name I could ask
But now it won't work for imported names:
|
@folone By using
|
PLS REBUILD ALL inferKind is ported. This solves kind with an elegant if statement: if(!tpe.isHigherKinded)
ProperTypeKind(tpe.asSeenFrom(pre, owner).bounds, tpe)
else { ... } Thanks @retronym for solving the ClassInfoType mystery. The verbose output now includes enhanced standard notation with bounds and variance:
I also added a limited String => Type facility. This allows me to write several types that was not supported previously:
|
(kitty-note-to-self: ignore 16032252) |
@adriaanm I took the type out of the kind. I was ignoring bounds that's the same as tpe, so now it comes out like this for proper types:
I don't know if this is correct/helpful. |
sorry, i got swamped and lost track of this I'd expect
|
I also expect Int and Foo's kind to be *, if anyone was waiting with bated breath for me to chime in. |
def starNotation: String | ||
|
||
private[internal] def buildString(sym: Symbol, variance: Variance, env: scala.collection.mutable.Map[Int, Int]): String | ||
protected def typeAlias(x: Int): String = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you import mutable at the top of the file, and refer to mutable.Map? I am not into the super long paths being inlined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mutable-map-as-method-parameter is almost invariably the wrong thing. Efficiency is no issue here, which removes the only imaginable defense. Please limit mutant wandering as much as possible.
:kind command diplays the kind of types and type constructors in Scala syntax notation. scala> :kind (Int, Int) => Int scala.Function2's kind is F[-A1,-A2,+A3]
Added a new commit reflecting @paulp's code review. I've accepted all points that were raised. Mainly, Kind now tries to avoid getting into the business of converting other objects ( Other changes:
The commits were growing, so I squashed them and rebased it off the current master. |
Any chance |
LGTM Thanks for patiently slogging through the PR maze. There are some refinements to be made before using the Kinds data structure more generally, but let's get this in already! (Here's my -- very late -- review:
|
Added a :kind command to the REPL
Nice! Thanks all for the feedback. |
Fixes scala/bug#8529 The :kind implementation added in scala#2340 was buggy and misleading in part because we could not find a robust way to turning type expression strings into Type. See also http://stackoverflow.com/questions/15678616/getting-type-information-inside-scala-repl-via-imain/15694003#15694003. The problem was that we didn't know how to pick up types defined in the REPL, so scala#2340 faked it by treating the expression as a term. That's the major source of problems reported in scala/bug#8529. This change improves the String to type symbol conversion by using `exprTyper.typeOfTypeString` repeatedly with `[Nothing]`. It's hacky, but a whole class of "expression" can now be called out as not being a type. Before: scala> :kind 5 scala.Int's kind is A After: scala> :kind 5 <console>:1: error: identifier expected but integer literal found. def $ires23: 5 = ??? ^ More importantly, it will no longer mix up companion objects with actual types. Before: scala> :kind -v Predef.Pair scala.Predef.Pair's kind is A * This is a proper type. After: scala> :kind -v Predef.Pair scala.Tuple2's kind is F[+A1,+A2] * -(+)-> * -(+)-> * This is a type constructor: a 1st-order-kinded type.
Fixes scala/bug#8529 The :kind implementation added in scala#2340 was buggy and misleading in part because we could not find a robust way to turn a type expression string into a Type. See also [Getting type information inside scala repl via IMain](http://stackoverflow.com/questions/15678616/getting-type-information-inside-scala-repl-via-imain/15694003#15694003). The problem was that we didn't know how to pick up types defined or imported in the REPL, so scala#2340 faked it by treating the given type expression as a term. That's the major source of problems reported in scala/bug#8529. This commit improves the String to type symbol conversion by using `exprTyper.typeOfTypeString` repeatedly with `[Nothing]`. It's hacky, but a whole class of "expression" can now be called out as not being a type. Before: scala> :kind 5 scala.Int's kind is A After: scala> :kind 5 <console>:1: error: identifier expected but integer literal found. def $ires23: 5 = ??? ^ More importantly, it will no longer mix up companion objects with actual types. Before: scala> :kind -v Predef.Pair scala.Predef.Pair's kind is A * This is a proper type. After: scala> :kind -v Predef.Pair scala.Tuple2's kind is F[+A1,+A2] * -(+)-> * -(+)-> * This is a type constructor: a 1st-order-kinded type.
Fixes scala/bug#8529 The :kind implementation added in scala#2340 was buggy and misleading in part because we could not find a robust way to turn a type expression string into a Type. See also [Getting type information inside scala repl via IMain](http://stackoverflow.com/questions/15678616/getting-type-information-inside-scala-repl-via-imain/15694003#15694003). The problem was that we didn't know how to pick up types defined or imported in the REPL, so scala#2340 faked it by treating the given type expression as a term. That's the major source of problems reported in scala/bug#8529. This commit improves the String to type symbol conversion by using `exprTyper.typeOfTypeString` repeatedly with `[Nothing]`. It's hacky, but a whole class of "expression" can now be called out as not being a type. Before: scala> :kind 5 scala.Int's kind is A After: scala> :kind 5 <console>:1: error: identifier expected but integer literal found. def $ires23: 5 = ??? ^ More importantly, it will no longer mix up companion objects with actual types. Before: scala> :kind -v Predef.Pair scala.Predef.Pair's kind is A * This is a proper type. After: scala> :kind -v Predef.Pair scala.Tuple2's kind is F[+A1,+A2] * -(+)-> * -(+)-> * This is a type constructor: a 1st-order-kinded type.
Fixes scala/bug#8529 The :kind implementation added in scala#2340 was buggy and misleading in part because we could not find a robust way to turn a type expression string into a Type. See also [Getting type information inside scala repl via IMain](http://stackoverflow.com/questions/15678616/getting-type-information-inside-scala-repl-via-imain/15694003#15694003). The problem was that we didn't know how to pick up types defined or imported in the REPL, so scala#2340 faked it by treating the given type expression as a term. That's the major source of problems reported in scala/bug#8529. This commit improves the String to type symbol conversion by using `exprTyper.typeOfTypeString` repeatedly with `[Nothing]`. It's hacky, but a whole class of "expression" can now be called out as not being a type. Before: scala> :kind 5 scala.Int's kind is A After: scala> :kind 5 <console>:1: error: identifier expected but integer literal found. def $ires23: 5 = ??? ^ More importantly, it will no longer mix up companion objects with actual types. Before: scala> :kind -v Predef.Pair scala.Predef.Pair's kind is A * This is a proper type. After: scala> :kind -v Predef.Pair scala.Tuple2's kind is F[+A1,+A2] * -(+)-> * -(+)-> * This is a type constructor: a 1st-order-kinded type.
Fixes scala/bug#8529 The :kind implementation added in scala#2340 was buggy and misleading in part because we could not find a robust way to turn a type expression string into a Type. See also [Getting type information inside scala repl via IMain](http://stackoverflow.com/questions/15678616/getting-type-information-inside-scala-repl-via-imain/15694003#15694003). The problem was that we didn't know how to pick up types defined or imported in the REPL, so scala#2340 faked it by treating the given type expression as a term. That's the major source of problems reported in scala/bug#8529. This commit improves the String to type symbol conversion by using `exprTyper.typeOfTypeString` repeatedly with `[Nothing]`. It's hacky, but a whole class of "expression" can now be called out as not being a type. Before: scala> :kind 5 scala.Int's kind is A After: scala> :kind 5 <console>:1: error: identifier expected but integer literal found. def $ires23: 5 = ??? ^ More importantly, it will no longer mix up companion objects with actual types. Before: scala> :kind -v Predef.Pair scala.Predef.Pair's kind is A * This is a proper type. After: scala> :kind -v Predef.Pair scala.Tuple2's kind is F[+A1,+A2] * -(+)-> * -(+)-> * This is a type constructor: a 1st-order-kinded type.
Description
Because Scala supports working with higher kinded types, we might want to be able to inspects kinds as well as types. This pull request adds a simple
:kind
command, implemented by @eed3si9n in his "Introduction to Scalaz: day 4" post, to the Scala REPL. Here is an example output:Future improvements
As pointed out by @retronym here, variance and type bounds are also part of the kind and we might want to include them in command's output.
Acknowledgements
The function for
:kind
feature is originally implemented by @eed3si9nI got a lot of help from @xeno-by and @retronym while working on this feature, thank you for that.
Happy Easter everyone!