I am writing a macro, that takes a function name,
and declares a couple of other version of the function.
I want to give these variations the same doc string as the original method,
with perhaps a few changes.
To do this, I need to retrieve the docstring for the orginal method.
So what I am looking for is a function:
get_docstring(functionname::Symbol, argtypes)::String
So that I could do:
julia> s=get_docstring(:values,(Associative,)) and then s would be set to:
s="""
values(a::Associative)
Return an iterator over all values in a collection.
`collect(values(d))` returns an array of values.
```jldoctest
julia> a = Dict('a'=>2, 'b'=>3)
Dict{Char,Int64} with 2 entries:
'b' => 3
'a' => 2
julia> collect(values(a))
2-element Array{Int64,1}:
3
2
```
"""
You can use the #doc macro, but instead of a string, it returns a markdown object:
julia> #doc "foo int" ->
foo(x::Int) = x
foo
julia> #doc "foo float" ->
foo(x::Float64) = x
foo
julia> #doc "foo sym" ->
foo(x::Symbol) = x
foo
julia> #doc "foo x, y" ->
function foo(x, y) x, y end
foo
julia> #doc foo
foo int
foo float
foo sym
foo x, y
julia> typeof(ans)
Base.Markdown.MD
julia> #doc foo(::Int)
foo int
julia> #doc foo(::Float64)
foo float
julia> #doc foo(::Symbol)
foo sym
julia> md = #doc foo(::Any, ::Any)
foo x, y
julia> md.content
1-element Array{Any,1}:
foo x, y
julia> md.content[1]
foo x, y
julia> md.content[1].content
1-element Array{Any,1}:
Base.Markdown.Paragraph(Any["foo x, y"])
julia> md.meta
Dict{Any,Any} with 3 entries:
:typesig => Tuple{Any,Any}
:results => Base.Docs.DocStr[Base.Docs.DocStr(svec("foo x, y"),foo x, y…
:binding => foo
julia>
Related
I am studying Julia static analysis, and I have the following function:
function f(x,y,z)
d=x+y
d=d*2*z
end
i use code_typed to analyze it.
julia> y=code_typed(f)
1-element Vector{Any}:
CodeInfo(
1 ─ %1 = (x + y)::Any
│ %2 = (%1 * 2)::Any
│ %3 = (%2 * z)::Any
└── return %3
) => Any
i can get slots and slot types of it.
julia> y[1].first.slotnames
5-element Vector{Symbol}:
Symbol("#self#")
:x
:y
:z
:d
julia> y[1].first.slottypes
5-element Vector{Any}:
Core.Const(f)
Any
Any
Any
Any
but do i have any way to know which is argument and which is local variables among the slots?
You can use Base.argnames to find out arguments of your function:
julia> Base.method_argnames.(methods(f))
1-element Vector{Vector{Symbol}}:
[Symbol("#self#"), :x, :y, :z]
You can extract this from the CodeInfo object as well:
julia> Base.method_argnames(y[1].first.parent.def)
4-element Vector{Symbol}:
Symbol("#self#")
:x
:y
:z
I am clearly missing something fundamental here. How can I change the second method of my function to accept c? Additionally, I would really prefer to use AbstractArray instead of AbstractVector as the type so as not to restrict the dimension either, but I wanted to cut down on potential sources of error.
function f(x::AbstractVector{Int})
println(x)
end # f (generic function with 1 method)
function f(x::AbstractVector{AbstractVector{Int}})
for i in x
println(i)
end
end # f (generic function with 2 methods)
a=[1,2,3] # 3-element Array{Int64,1}:
b=[4,5,6] # 3-element Array{Int64,1}:
c=[a,b] # 2-element Array{Array{Int64,1},1}:
typeof(a) <: AbstractVector{Int} # true
typeof(c) <: AbstractVector{AbstractVector{Int}} # false
f(a) # [1, 2, 3]
f(c) # ERROR: MethodError: no method matching f(::Array{Array{Int64,1},1})
Quoting the manual:
Concrete Point types with different values of T are never subtypes of each other:
julia> struct Point{T} end
julia> Point{Float64} <: Point{Int64}
false
julia> Point{Float64} <: Point{Real}
false
This last point is very important: even though Float64 <: Real we DO NOT have Point{Float64} <: Point{Real}.
Translated to your example, as you noted,
julia> Vector{Int} <: AbstractVector{Int}
true
julia> Vector{Vector{Int}} <: AbstractVector{AbstractVector{Int}}
false
What you need here is
julia> Vector{Vector{Int}} <: AbstractVector{T} where T <: AbstractVector{Int}
true
or the convenient shorthand
julia> Vector{Vector{Int}} <: AbstractVector{<:AbstractVector{Int}}
true
I am trying to convert a python script to Julia. I am checking to make sure I am doing this code in the most optimal way. Please see the following code:
julia> a = [1,2,3,4,5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> if 1 in a
print("1 is in a")
end
1 is in a
julia> if 6 not in a
print("6 not in a")
end
ERROR: TypeError: non-boolean (Int64) used in boolean context
Stacktrace:
[1] top-level scope at REPL[6]:1
julia> push!(a, 6)
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> if (6 in a) == true
print("6 in a")
end
6 not in a
julia> b = [1]
1-element Array{Int64,1}:
1
julia> if (6 in b) == true
print("6 in b")
end
Am I doing this "not in" check correctly?
julia> a = [1, 2, 3, 4, 5];
julia> 6 ∉ a
true
The ∉ symbol can be typed in the REPL by typing \notin and then hitting TAB. Of course, the ∈ symbol is also available as an alternative to in by typing \in and hitting TAB:
julia> 6 ∈ a
false
Sometimes you need a vectorized version:
julia> x = [2, 7];
julia> x .∉ Ref(a)
2-element BitArray{1}:
0
1
The Ref is needed in this case so that a is treated as a scalar in the broadcasting operation.
If you prefer to avoid Unicode characters, you can write !(6 in a) instead of 6 ∉ a.
I am trying to define a function wrapper that curries a tuple in SML.
fun curry f = fn (x, y) z => f x y z;
Gives me the error
Non-identifier applied to a pattern.
I am new to ML and not sure why the pattern matching in fn doesn't work.
How could I make this work?
I am trying to define a function wrapper that curries a tuple in SML.
fun curry f = fn (x, y) z => f x y z;
How could I make this work?
Closures in SML don't allow for multiple arguments, but you can nest them instead.
What curry usually does is take a function f that normally accepts a tuple (x, y) and instead returns a modified function that takes x and y separately. Here is a number of equivalent ways to define curry:
fun curry f x y = f (x, y)
fun curry f x = fn y => f (x, y)
fun curry f = fn x => fn y => f (x, y)
val curry = fn f => fn x => fn y => f (x, y)
Its opposite, uncurry instead takes a function f that takes x and y separately and returns a modified function that takes (x, y). Here is one way to write uncurry:
fun uncurry f (x, y) = f x y
It's easy to mix up the two.
One way to fix the function you've written so that it compiles is insert an extra => fn:
fun what_is_this f = fn (x, y) => fn z => f x y z
(* ^- there *)
Before giving it a name, let's analyse what it does. It has the type signature:
fn : ('a -> 'b -> 'c -> 'd) -> 'a * 'b -> 'c -> 'd
(* now a tuple -^ ^- still curried *)
meaning that it takes a function of three curried arguments (x, y and z) and returns a modified function where the first two arguments are now in a tuple (uncurried) and the third is still curried. This is really a less generic version of uncurry. A more clear way of writing it would be:
fun what_is_this f (x, y) z = f x y z
If you use uncurry on a function of three arguments, you get the same effect, but you can't use what_is_this on anything with two curried arguments. So I'd say that this is a less useful variant of uncurry.
There are however other more useful variants of curry/uncurry. For example, you could make an uncurry_twice that converts f x y z into (uncurry_twice f) ((x, y), z), or an uncurry3 that converts f x y z into (uncurry3 f) (x, y, z):
fun uncurry_twice f = uncurry (uncurry f)
fun uncurry3 f (x, y, z) = f x y z
I would like to create a quote which gets the symbol :abc saved in variable x and push it into the array a. However I could only get the variable abc. The syntax :$x seems incorrect (not what I desired). What is the syntax to do this?:
julia> x = :abc
julia> expr = quote
a = []
push!(a, $x)
push!(a, :($x))
push!(a, :$x)
a
end
quote
a = []
push!(a, abc)
push!(a, $(Expr(:quote, :($(Expr(:$, :x))))))
push!(a, :$ * x)
a
end
The desired output is:
quote
a = []
push!(a, :abc)
a
end
You need to add another layer of quotation, using $(Meta.quot(:abc)) which is equivalent to $(Expr(:quote, :abc)).
Using:
_
_ _ _(_)_ | A fresh approach to technical computing
(_) | (_) (_) | Documentation: https://docs.julialang.org
_ _ _| |_ __ _ | Type "?help" for help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 0.6.2 (2017-12-13 18:08 UTC)
_/ |\__'_|_|_|\__'_| | Official http://julialang.org/ release
|__/ | x86_64-pc-linux-gnu
Setup:
julia> x = :abc
:abc
julia> es = [x, :x, :(:x), Expr(:quote, x), Meta.quot(x)] # :(x) is parsed as :x
5-element Array{Any,1}:
:abc
:x
:(:x)
:(:abc)
:(:abc)
julia> blk = Expr(:block)
quote
end
Push!:
julia> push!(blk.args, :(a = []))
1-element Array{Any,1}:
:(a = [])
julia> blk
quote
a = []
end
julia> for e in es
push!(blk.args, :(push!(a, $e)))
end
julia> blk
quote
a = []
push!(a, abc)
push!(a, x)
push!(a, :x)
push!(a, :abc)
push!(a, :abc)
end
julia> push!(blk.args, :a)
7-element Array{Any,1}:
:(a = [])
:(push!(a, abc))
:(push!(a, x))
:(push!(a, :x))
:(push!(a, :abc))
:(push!(a, :abc))
:a
Eval:
julia> blk
quote
a = []
push!(a, abc)
push!(a, x)
push!(a, :x)
push!(a, :abc)
push!(a, :abc)
a
end
julia> eval(ans)
ERROR: UndefVarError: abc not defined
Stacktrace:
[1] eval(::Module, ::Any) at ./boot.jl:235
[2] eval(::Any) at ./boot.jl:234
Fix:
julia> deleteat!(blk.args, 2)
6-element Array{Any,1}:
:(a = [])
:(push!(a, x))
:(push!(a, :x))
:(push!(a, :abc))
:(push!(a, :abc))
:a
julia> blk
quote
a = []
push!(a, x)
push!(a, :x)
push!(a, :abc)
push!(a, :abc)
a
end
julia> eval(ans)
4-element Array{Any,1}:
:abc
:x
:abc
:abc
Finally:
julia> using Base.Meta: quot
julia> x = :abc
:abc
julia> expr = quote
a = []
push!(a, $(quot(x)))
a
end
quote
#= REPL[16]:2 =#
a = []
#= REPL[16]:3 =#
push!(a, :abc)
#= REPL[16]:4 =#
a
end
julia> eval(ans)
1-element Array{Any,1}:
:abc