Suppose I have an expression like :(Main.i / (0.5 * Main.i * sin(Main.i)).
I would like to replace each occurence of Main.i into some other symbol. Is there an idiomatic way to do this in Julia?
Main.i is not a symbol but an expression, which you can check by doing dump(:(Main.i)).
Here is a quick writeup what I think might match your needs:
function expr_replace(expr, old, new)
expr == old && return new
if expr isa Expr
expr = deepcopy(expr) # to avoid mutation of source
for i in eachindex(expr.args)
expr.args[i] = expr_replace(expr.args[i], old, new)
end
end
expr
end
Does it work for you?
EDIT: Here is a version that does a minimal safe use of deepcopy:
function expr_replace(expr, old, new)
function f(expr)
expr == old && return deepcopy(new)
if expr isa Expr
for i in eachindex(expr.args)
expr.args[i] = f(expr.args[i])
end
end
expr
end
f(deepcopy(expr))
end
In general I guess this will not matter that much as you probably will not want to pass 100 lines of code through this function.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I want to understand how expressions work in Ocaml.
For example, I have :
type expr =
Int of int
| Var of string
| Sum of expr * expr
| Diff of expr * expr
| Mult of expr * expr
| Div of expr * expr
How can I recognise if an element is an expression?
I was think to something like expr -> expr -> bool :
let subexpression express1 express2 =
if express1 express1 then true else false
let E1 = 3 x 8 in
let E2 = 5/6 in
if subexpression E1 E2 then print_strin "true" else print_string "false"
I haven't test the code because this is what I'm thinking, but actually I don't know how to write it...
You need to be clear on whether you're asking about expressions in OCaml generally or values of the type expr that you define here.
Because OCaml is a strongly typed language, you can't have a value of type expr that's not well formed. So there's no meaningful function to test whether something of type expr is an expression. (You could define a function that always returns true.)
On the other hand, your proposed function has two expression parameters. This doesn't make a lot of sense either. What is the purpose of these two parameters?
Other parts of your question suggest that you want to determine whether one expression is a subexpression of another. That's a different question entirely.
You can look through an value of type expr by working recursively through the different cases. The basic framework of a function for traversing such a value would look something like this:
let myfunc expr =
match expr with
| Int n -> (* do something n, an int *)
| Var s -> (* do something with s, a string *)
| Sum (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
| Diff (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
| Mult (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
| Div (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
It's hard to say more than this because your question is hard to understand, (and it frankly doesn't look like you've put in very much work on it yet).
In my equations we have many expressions with a^2, and so on. I would like to map "²" to ^2, to obtain something like that:
julia> a² == a^2
true
The above is not however a legal code in Julia. Any idea on how could I implement it ?
Here is a sample macro #hoo that does what you requested in a simplified scenario (since the code is long I will start with usage).
julia> x=5
5
julia> #hoo 3x² + 4x³
575
julia> #macroexpand #hoo 2x³+3x²
:(2 * Main.x ^ 3 + 3 * Main.x ^ 2)
Now, let us see the macro code:
const charsdict=Dict(Symbol.(split("¹²³⁴⁵⁶⁷⁸⁹","")) .=> 1:9)
const charsre = Regex("[$(join(String.(keys(charsdict))))]")
function proc_expr(e::Expr)
for i=1:length(e.args)
el = e.args[i]
typeof(el) == Expr && proc_expr(el)
if typeof(el) == Symbol
mm = match(charsre, String(el))
if mm != nothing
a1 = Symbol(String(el)[1:(mm.offset-1)])
a2 = charsdict[Symbol(mm.match)]
e.args[i] = :($a1^$a2)
end
end
end
end
macro hoo(expr)
typeof(expr) != Expr && return expr
proc_expr(expr)
expr
end
Of course it would be quite easy to expand this concept into "pure-math" library for Julia.
I don't think that there is any reasonable way of doing this.
When parsing your input, Julia makes no real difference between the unicode character ² and any other characters you might use in a variable name. Attempting to make this into an operator would be similar to trying to make the suffix square into an operator
julia> asquare == a^2
The a and the ² are not parsed as two separate things, just like the a and the square in asquare would not be.
a^2, on the other hand, is parsed as three separate things. This is because ^ is not a valid character for a variable name and it is therefore parsed as an operator instead.
suppose that I have a macro that is defined as :
macro foomacro(ex::Expr)
dump(ex)
ex
end
Currently I would like to pass my expression as a parsed string so that I may pass a rather complicated and case dependent expression that has been obtained via string concatenation.
However, trying :
#foomacro 1+2+3
gives the expected result 6 whereas
#foomacro parse("1+2+3")
returns the parsed expression :(1+2+3) instead of actually parsing it...
As far as I understand this both macros should be receiving the same expression but this is clearly not the case.
How do I get this MWE to work ?
ps: I figured out this fix but I feel like it is very dirty and "incorrect"
macro foomacro(ex::Expr)
if ex.head == :call
#in this case the user is calling the macro via a parsed string
dump(ex)
return ex
end
dump(ex)
ex
end
ps: if this is of any relevance, currently the code is running on 0.6.4 and if possible I'd rather not update to 1.0 yet since this would postpone my actual project to much...
You're mixing up levels. Let's introduce an intermediate function for clarity:
function foomacro_impl(expr)
dump(expr)
expr
end
macro foomacro(expr)
foomacro_impl(expr)
end
If run, the expression #foomacro <someexpr> will be parsed, the <someexpr> part passed to foomacro_impl, and the result treated as an expression and inserted instead of the original expression. That means that writing #foomacro 1+2+3 is equivalent to having written
let expr = :(1+2+3)
dump(expr)
expr
end
which returns
Expr
head: Symbol call
args: Array{Any}((4,))
1: Symbol +
2: Int64 1
3: Int64 2
4: Int64 3
:(1 + 2 + 3)
an Expr that evaluates to 6.
On the other hand, in #foomacro Meta.parse("1+2+3"), the whole argument, parse("1+2+3"), is used as expr:
julia> let expr = :(Meta.parse("1+2+3"))
dump(expr)
expr
end
Expr
head: Symbol call
args: Array{Any}((2,))
1: Expr
head: Symbol .
args: Array{Any}((2,))
1: Symbol Meta
2: QuoteNode
value: Symbol parse
2: String "1+2+3"
:(Meta.parse("1+2+3"))
So the result of the macro call is the expression Meta.parse("1+2+3"), which evaluates to another expression :(1 + 2 + 3), since it is a call to parse. The two forms are thus not receiving the same expression!
But there are ways to manually parse an expression and pass it to a macro:
You can do as I did, and use a separate "macro implementing function". Then, the expression returned by #foomacro bla is equivalent to foomacro_impl(Meta.parse(bla)). (This approach, BTW, is very useful for testing, and I recommend it most of the times.)
You can use the macro #eval to construct an expression, splice into it, and evaluate it immediately:
julia> #eval #foomacro $(Meta.parse("1+2+3"))
Expr
head: Symbol call
args: Array{Any}((4,))
1: Symbol +
2: Int64 1
3: Int64 2
4: Int64 3
6
(Or similarly, use eval and manually constructed Expr values.)
I followed the documentation of julia:
julia> :(a in (1,2,3))
:($(Expr(:in, :a, :((1,2,3)))))
Now that :(a in (1,2,3))==:($(Expr(:in, :a, :((1,2,3))))), why does julia express this expression in this way? And what does $ exactly means? It seems to me that $ just evaluates the next expression in a global scope. I found the documentation unclear about this.
The reason :(a in (1,2,3)) is displayed awkwardly as :($(Expr(...))) is because the show function for Expr typed objects (show_unquoted in show.jl) does not understand the in infix operator and fallbacks into a generic printing format.
Essentially it is the same as :(1 + 1) except that show_unquoted recognizes + as an infix operator and formats it nicely.
In any case, :(...) and $(...) are inverse operators in some sense, so :($(..thing..)) is exactly like ..thing.., which in this case is Expr(:in,:a,:((1,2,3))).
One can see this weirdness in :(1+1) for example. The output is of Expr type, as typeof(:(1+1))==Expr confirms. It is actually Expr(:+,1,1), but typing Expr(:+,1,1) on the REPL will show :($(Expr(:+,1,1))) - the generic formatting style of Expr typed objects.
Fixing show.jl to handle in could be a nice change. But the issue is harmless and concerns display formatting.
$ is the interpolation command, Julia use this notation to interpolate Strings as well as Expression:
julia> a=1;
julia> "test $a" # => "test 1"
julia> :(b+$a) # => :(b + 1)
When you type a command in Julia REPL, it tries to evaluates the command and if the code do not have ; char at the end it prints the result, so it's more related to printing functions, that what will be seen on REPL, when a command executes.
so if you want to see the real contents of a variable one possibility is to use dump function:
julia> dump(:(a+b))
Expr
head: Symbol call
args: Array(Any,(3,))
1: Symbol +
2: Symbol a
3: Symbol b
typ: Any
julia> dump(:(a in b))
Expr
head: Symbol in
args: Array(Any,(2,))
1: Symbol a
2: Symbol b
typ: Any
It's clear from above tests, that both expressions use a common data structure of Expr with head, args and typ without any $ inside.
Now try to evaluate and print result:
julia> :(a in b)
:($(Expr(:in, :a, :b)))
julia> :(a+b)
:(a + b)
We already know that both command create a same structure but REPL can't show the result of :(a in b) better that an Expr of result of another Expr and it's why there in a $ inside. But when dealing with :(a+b), REPL do more intelligently and understands that this:
Expr
head: Symbol call
args: Array(Any,(3,))
1: Symbol +
2: Symbol a
3: Symbol b
typ: Any
is equal to :(a+b).
I would like to create a function with a symbol (for instance, ~), which works similarly to the "question mark" function.
You can't do something as "bare" as ?foo without messing with the C code that defines the syntax of R. For example, you can't make [fnord be meaningful.
This comes from the syntax definition in gram.y in the R sources.
| '~' expr %prec TILDE { $$ = xxunary($1,$2); }
| '?' expr { $$ = xxunary($1,$2); }
| expr ':' expr { $$ = xxbinary($2,$1,$3); }
| expr '+' expr { $$ = xxbinary($2,$1,$3); }
The second line above defines the syntax for ?foo. What exactly are you trying to do?
You can make functions and variables with arbitrary names, via use of the backtick `.
`~` <- `+`
y <- 5
x <- 10
y ~ x
# 15
I wouldn't mess with ~ though, unless you don't intend to do any statistical modelling....