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

Optional matching #42

Open
Qiyamah opened this issue Aug 25, 2017 · 8 comments
Open

Optional matching #42

Qiyamah opened this issue Aug 25, 2017 · 8 comments

Comments

@Qiyamah
Copy link

Qiyamah commented Aug 25, 2017

Hi,

@metafunction fte(function f(*{args}):::?{rt} *{stmts} end) begin
  println(f)
  println(args)
  println(rt)
  println(stmts)
end

is supposed to match something like :
:(function f(x,y) x+y end) or
:(function f(x,y)::Int x+y end)
but it is unable to match against
:(function f(x,y) x+y end)

? means reluctant match right? Doesn't this means it may match nothing?

Thanks

@fcard
Copy link
Owner

fcard commented Aug 25, 2017

It's a slurp, so it can only match a variable number of elements in a single syntax type e.g. f(:?{args}), where f(...) is still a :call syntax type no matter how many args there are, whereas in your case if there is a rt the type is :(::), otherwise :call.

What you want is some sort of "optional" special syntax, which there isn't one yet. Right now you need to use two methods:

@metafunction fte(function f(*{args}); *{stmts} end) = 
  fte(:(function f($(args...))::Any; $(stmts...) end))

@metafunction fte(function f(*{args})::T; *{stmts} end) begin
  println(f)
  println(args)
  println(T)
  println(stmts)
end

It shouldn't be too difficult making a :O/:opt/:optional special syntax so that you can write

@metafunction fte(function f(*{args})::(:opt{T, Any}); *{stmts} end)
  ...
end

I can work on that if you think that's a desirable feature.

@Qiyamah
Copy link
Author

Qiyamah commented Aug 25, 2017

Thanks, that is what i have done too,
It seems i better get involved in development of this package.
I will start by implementing the opt special syntax and send you a pull request.

Thanks

@fcard
Copy link
Owner

fcard commented Aug 25, 2017

Thanks for the interest! If you need any help feel free to submit a WIP and/or ask any questions.

@fcard fcard changed the title :? matching Optional matching Aug 25, 2017
@Qiyamah
Copy link
Author

Qiyamah commented Aug 26, 2017

Hi,

I am implementing the :O or :optional special for the following syntax matching:

@metafunction fte(function f(*{args})(:O{:L{::}:A{rt}}); *{stmts} end)
  ...
end

So I am thinking to implement this as a special PatternGate, then I should check whether there is a match if not roll back and continue with the other child of the parent node.
Does this sound right to you? And do you have suggestions as well?

Thanks

@fcard
Copy link
Owner

fcard commented Aug 26, 2017

Remember that julia expressions are tree-like, so that pattern can't work. f(x)::T parses as

(:: (call f x) T)

Not

(f ( x ) :: T)

Or some other vector-like shape. I recommend using dump on expressions you want to match to understand their structure better.


My idea for an implementation would look like this:

f(*{args})::(:O{rt})
f(*{args})::(:O{rt, Any})

Otherwise behaving about the same way as you described (If I understood correctly), but working from the parent node instead of the :optional node. Specifically, you would need to:

  • Make the analyzer check each children of a node for optional patterns and track that in some way in the parent node (preferably by wrapping it in a specialized type). If a pattern has optionals, it must have one (and only one) obligatory child, otherwise throw an error.
    e.g. f(x, :O{y}) is invalid, as is (:O{f(x)})::(:O{rt})
  • Make the matcher check for each node if that node has optional children; if not, match normally, otherwise:
    • Try matching the expression to the entire pattern without adding variables to the main Vars dictionary (possibly adding them to another dictionary to avoid having to match the pattern twice, and just transferring the bindings from the optional dict to the main dict if successful)
    • On failure, try matching the expression with the single obligatory child, if successful bind each optional name to its default value. (if none is provided, bind it to nothing)

@Qiyamah
Copy link
Author

Qiyamah commented Aug 28, 2017

I think following symbol of | as an OR is much more better to match,

In the following pattern, the second argument is optional:

function (name(*{args}) | :O{::rt}) *{stats} end

it tries to match name({args}) or name({args})::rt

In the following pattern, the second argument is not optional, this means straight forward OR

function (name(*{args}) | name(*{args})::rt) *{stats} end

@fcard
Copy link
Owner

fcard commented Aug 28, 2017

If you use normal julia syntax like (x | y), then we can't match expressions like (x | y). That's why I picked an unlikely to be used syntax like :name{...}. So at best you can do :or{x, y}.

I thought about the :or idea too but it's hard to figure out a simple to explain set of semantic rules for it. If two expressions have different names, what happens to the names of the one not matched? Bound to nothing? And if so there is no way to bind a default value, so it's. worse than an optional argument. What happens when both patterns can be matched? In :or{x, x+y}, error or same rules as dispatch? Bleh, no, I don't like it. We already have dispatch for true or clauses, the only case I can think of where or wouldn't add a lot more complexity in exchange for very little work removed is the optional case.

I don't understand your first example. Does :O in this case catch the other expression and graft it in the inner argument? How are we to know where? How would we say (:opt{x}, y)? You can't do ((,y) | :opt{x}), that's not valid syntax. How is this simpler than just using :opt without | or :or ?

(also, function :or{name(*{args}), name(*{args})::rt} *{stats} end and function :or{name(*{args}), :O{::rt}} *{stats} end both cause syntax errors, and I am not willing to sacrifice (x | y) matching.)

@fcard
Copy link
Owner

fcard commented Oct 31, 2017

Hi @Qiyamah, do you still want to do this? Just checking because I might refactor a lot of code soon and might end up taking a look at this in the process if you can't or don't want to work on it.

You've already done a lot for the project just by showing interest, I would have probably just given up on this if not for that (your ideas and bug reports were very much appreciated too!), so don't worry about dropping this if you've lost interest/got busy/etc, you've been a great help already.

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

No branches or pull requests

2 participants