Skip to content
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

Pattern matching on Maybe <function> causes compilation error. #427

Closed
TheGrandmother opened this issue May 20, 2016 · 10 comments
Closed

Pattern matching on Maybe <function> causes compilation error. #427

TheGrandmother opened this issue May 20, 2016 · 10 comments

Comments

@TheGrandmother
Copy link
Contributor

Compiling the following program:

class Main
    def main() : void {
    let bob = Just (λ(a: int) → a+1) : Maybe (int → int);
    match bob with
      Just x ⇒ print "Yhay"
      Nothing ⇒ print "Nay"
    }

produces this compiler error (with the -v flag):

== Reading file 'test.enc' ==
== Parsing ==
== Expanding modules ==
== Desugaring ==
== Prechecking ==
== Typechecking ==
== Optimizing ==
== Generating code ==
encorec: Maybe.fromJust: Nothing
@ghost
Copy link

ghost commented May 23, 2016

class Main
  def main() : void {
    let bob = Just (\(a: int) -> a+1) : Maybe (int -> int);
    match bob with
      Just x => print "Yhay"
      Nothing => print "Nay"
  }

^ Copy pastable version for those of us who don't have that special vim mode.

Note that the following program generates the same error so the Maybes don't actually have anything to do with how the error arises:

class Main
  def main() : void {
     let bob =  (\(a: int) -> a+1) : int -> int;
     match bob with
       x => print "Yhay"
       _ => print "Nay"
  }

@ghost
Copy link

ghost commented May 23, 2016

On line 840 in back/CodeGen/Expr.hs we find the following code:

          let freeVars = filter (not . Ty.isArrowType . snd) $
                                Util.freeVariables [] (A.mcpattern clause)

The goal is to find the names of the new variables introduced by the pattern. To do that we are filtering out those with function type in order to get rid of the object patterns. If we remove the filter your example compiles but we instead can't compile examples like this one (the important feature of the example is that the name of a variable pattern is the same as the name of an object pattern):

passive class IntContainer
  x: int
  def init(x: int): void
    this.x = x

  def IntContainer(): Maybe int
    Just this.x

class Main
  def main(): void
    match new IntContainer(3) with
      IntContainer(IntContainer) => print IntContainer

Allthough that might be a good thing. What do you guys think? If this should compile then we'll have to write a new custom function to extract the free variables from the pattern. If we don't want it to compile then we'll have to add some extra error checking to the typechecker.

@supercooldave
Copy link

Presumably it is the last line you are referring to. That looks evil, though I cannot formula a good reason why it is evil.

@TheGrandmother
Copy link
Contributor Author

TheGrandmother commented May 23, 2016

I agree with @supercooldave. In this case it looks extremely odd. My brain does not parse that.
My brain kinda melts when looking at that.
So the IntContainer is both the value of the new IntContainer(3) and the constructor?

I think the weirdness of this comes from the implicit assumption that the expression new Foo(x)
returns something called Foo the isn't really the the class Fooor the object returned by calling the constructor of Foo but some other thing?
If I have understood it right.

I'm very confused.

@supercooldave
Copy link

The fact that the program uses extractor methods makes the program look odd, if you don't know about extractor methods (if that's what they are called). But that's not what I find weird. It's the use of a 'global' name IntContainer right next to a locally introduced occurrence of the same name.

@ghost
Copy link

ghost commented May 23, 2016

passive class IntContainer
  x: int
  def init(x: int): void
    this.x = x

  def IntContainer(): Maybe int
    Just this.x

class Main
  def main(): void
    match new IntContainer(3) with
      IntContainer(x) => print x

The program is the same as this one, except some wierdo used IntContainer as a variable name instead of x. We can further change the example to this:

passive class IntContainer
  x: int
  def init(x: int): void
    this.x = x

  def MyCustomPattern(): Maybe int
    Just this.x

class Main
  def main(): void
    match new IntContainer(3) with
      MyCustomPattern(x) => print x

And then the question turns into whether this should compile or not:

passive class IntContainer
  x: int
  def init(x: int): void
    this.x = x

  def MyCustomPattern(): Maybe int
    Just this.x

class Main
  def main(): void
    match new IntContainer(3) with
      MyCustomPattern(MyCustomPattern) => print MyCustomPattern

And yes they're called extractors in Scala. Though I've been promoting the name object patterns since extractors is Scala specific and the idea really is both older and more widespread than Scala, though Scala definitely is the largest language by far which includes them.

@supercooldave
Copy link

Object Patterns is a nicer name.

@TheGrandmother
Copy link
Contributor Author

No no no. the last one should not compile IMO.

Having the MyCustomPattern only be the actual extractor method makes waaaay more sense than introducing a new local variable with the same name.
I can't think of any situation where the last one makes any sense.

And if this is the trade-of we need to do to have pattern matching on functions it is totally worth it.

@supercooldave
Copy link

It should not compile.

@ghost
Copy link

ghost commented May 23, 2016

No Henrik, we can have matching on functions either way. Its just that the way we get it differs depending on whether that code example should compile or not.

I asked Elias about it and he was of the mind that "it should compile, but the author ought to be shot". Anyways, since everyone at least agrees that it is awful code I'll go ahead and start working on a PR that fixes this issue and gives a type-error for my example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants