Giter VIP home page Giter VIP logo

patterndispatch.jl's Introduction

Build Status

PatternDispatch.jl

To install, simply type

] add https://github.com/MasonProtter/PatternDispatch.jl.git

at the julia REPL.


PatternDispatch.jl offers pattern matching through Rematch.jl but with extensible, multiple-dispatch like semantics.

using PatternDispatch
@pattern fib(x) = fib(x-1) + fib(x-2)
@pattern fib(1) = 1
@pattern fib(0) = 0
julia> fib(10)
55

Now suppose I later decide I don't want a stack overflow every time I accidentally call fib(-1), then I can just define

@pattern fib(x where x < 0) = error("Fib only takes positive inputs.")
julia> fib(-1)
ERROR: Fib only takes positive inputs.

Any valid Rematch.jl pattern can be used in a @pattern function signature, so you can write powerful destructuring code like

@pattern foo(x) = x
@pattern foo([x]) = x
@pattern foo((x,) where x < 1) = 1
@pattern foo((x,) where (x isa String || x > 1)) = x*x
@pattern foo(Expr(:call, [:+, a, b])) = a * b
julia> foo(1)
1

julia> foo([2])
2

julia> foo((0.5,))
1

julia> foo((1.5,))
2.25

julia> foo(("hi",))
"hihi"

julia> foo(:(3 + 2))
6

Pattern 'methods' are dispatched on in order of their specificity, so completely unconstrained patterns like @pattern f(x) have the lowest precedence whereas exact value patterns like @pattern f(1) have highest precedence. Constrained patterns like @pattern f(x, y where y > x) have intermediate precedence. For instance, the above function foo has a function body like

foo(args...) = foo(Pattern, args...)

foo(::Type{Pattern}, args...) = @match args begin
    (Expr(:call, [:+, a, b]),)          => a * b
    ((x,) where x isa String || x > 1,) => x * x
    ((x,) where x isa String || x > 1,) => -1
    ((x,) where x < 1,)                 => 1
    ([x],)                              => x
    (x,)                                => x
end

where @match is from the Rematch.jl package.

Adding pattern methods to functions you don't own

Suppose we want to add pattern matching methods to functions from other modules, e.g. we are annoyed that sin(2π) != 0.0 and want to change it. If we naively write

julia> @pattern Base.sin(x where x == 2π) = 0.0
sin (generic function with 13 methods)

julia> sin(2π)
-2.4492935982947064e-16

we don't get the result we might have expected. This is because overwriting the regular sin(x) method would be type piracy. To avoid type piracy, PatternDispatch.jl created a method sin(::Type{Pattern}, args...) = @match ... but not an accompanying method sin(args...) = sin(Pattern, args...), so to access our new method we need to do

julia> sin(Pattern, 2π)
0.0

directly.

Known Gotcha's

  • Due to an unfortunate implementation detail, pattern functions are all @generated functions, meaning that they cannot return closures (there are workarounds to this, see the 'closures' testset in tests/runteses.jl).
  • If you define a @pattern function in a local scope, you may get errors if you reference variables defined in that scope, even the pattern function itself ref.

patterndispatch.jl's People

Contributors

masonprotter avatar singularitti avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

patterndispatch.jl's Issues

Pattern closures not supported

Currently, pattern functions are generated functions so the following happens:

julia> using PatternDispatch

julia> @pattern f(x) = y -> y + x
f (generic function with 2 methods)

julia> f(1)
ERROR: The function body AST defined by this @generated function is not pure. This likely means it contains a closure or comprehension.
Stacktrace:
 [1] f(::Int64) at /Users/mason/Documents/Julia/PatternDispatch/src/PatternDispatch.jl:46
 [2] top-level scope at REPL[3]:1

I've tried switching to using @gg from GeneralizedGenerated.jl but get some errors I haven't had time to figure out:

julia> using PatternDispatch

julia> @pattern f(x) = y -> y + x
f (generic function with 2 methods)

julia> f(1)
ERROR: MethodError: Cannot `convert` an object of type Expr to an object of type Symbol
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:168
  Symbol(::Any...) at strings/basic.jl:206
Stacktrace:
 [1] GeneralizedGenerated.NGG.Argument(::Expr, ::Nothing, ::GeneralizedGenerated.NGG.Unset) at /Users/mason/.julia/packages/GeneralizedGenerated/NDqgV/src/ngg/runtime_fns.jl:19
 [2] of_args(::Array{GeneralizedGenerated.FuncArg,1}) at /Users/mason/.julia/packages/GeneralizedGenerated/NDqgV/src/func_arg_decs.jl:61
 [3] ##GeneralizedGenerated 237#707#59 at /Users/mason/.julia/packages/GeneralizedGenerated/NDqgV/src/closure_conv.jl:45 [inlined]
 [4] ##GeneralizedGenerated 235#705#58 at ./none:0 [inlined]
 [5] ##GeneralizedGenerated 228#698#57 at ./none:0 [inlined]
 [6] ##GeneralizedGenerated 226#696#56 at ./none:0 [inlined]
 [7] (::GeneralizedGenerated.var"#conv#53"{Module})(::Expr) at /Users/mason/.julia/packages/GeneralizedGenerated/NDqgV/src/closure_conv.jl:27
 [8] closure_conv(::Module, ::Expr) at /Users/mason/.julia/packages/GeneralizedGenerated/NDqgV/src/closure_conv.jl:78
 [9] #s21#8(::Any, ::Any, ::Any) at /Users/mason/.julia/packages/GeneralizedGenerated/NDqgV/src/closure_conv.jl:121
 [10] (::Core.GeneratedFunctionStub)(::Any, ::Vararg{Any,N} where N) at ./boot.jl:524
 [11] f(::Int64) at /Users/mason/Documents/Julia/PatternDispatch/src/PatternDispatch.jl:46
 [12] top-level scope at REPL[3]:1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.