Pass keyword argument to a macro in julia - macros

I'd like to pass a keyword argument to a macro in julia. I try to parse the kwargs manually and build the Expr but got errors. Do I miss something?
macro sort(x, kv)
#show x,kv
d = []
if kv.head == :(=)
# push!(d, (kv.args[1], kv.args[2])) # fail
push!(d, (kv.args[1], esc(kv.args[2]))) # fail also
end
ex = quote
sort($x; $(d...))
end
Meta.show_sexpr(ex)
ex
end
x = collect(1:5)
rev=true
#sort x rev=rev
Output:
(x, kv) = (:x, :(rev = rev))
(:block,
(:line, 9, Symbol("REPL[36]")),
(:call, :sort, (:parameters, (:rev, :($(Expr(:escape, :rev))))), :x)
)ERROR: TypeError: non-boolean (Expr) used in boolean context
Stacktrace:
[1] (::Base.#kw##sort!)(::Array{Any,1}, ::Base.#sort!, ::Array{Int64,1}) at ./<missing>:0
[2] #sort#8(::Array{Any,1}, ::Function, ::Array{Int64,1}) at ./sort.jl:546
[3] (::Base.#kw##sort)(::Array{Any,1}, ::Base.#sort, ::Array{Int64,1}) at ./<missing>:0
[4] macro expansion at ./REPL[36]:9 [inlined]
[5] anonymous at ./<missing>:?
Edit: I am able to build keyword args using :parameters Expr. My generated Expr looks like the normal one. But strangely, I got the error "syntax: invalid syntax (parameters (kw (outerref rev) true))"
julia> macro m(f, x, ks...)
#show f x ks
ex = Expr(:call, f, x)
par = Expr(:parameters )
push!(ex.args, par)
for kv∈ks
k,v = kv.args
push!(par.args, Expr(:kw, k, v))
end
Meta.show_sexpr(ex)
ex
end
#m (macro with 1 method)
julia>
julia> Meta.show_sexpr(:(sort(1:9; rev=true)))
(:call, :sort, (:parameters, (:kw, :rev, true)), (:(:), 1, 9))
julia> #m sort 1:9 rev=true
f = :sort
x = :(1:9)
ks = (:(rev = true),)
(:call, :sort, (:(:), 1, 9), (:parameters, (:kw, :rev, true)))ERROR: syntax: invalid syntax (parameters (kw (outerref rev) true))

Related

How to type-hint in Hy

Is it possible to type-hint variables and return values of functions in Hy language?
# in python we can do this
def some_func() -> str:
return "Hello World"
Yes... Hy implements PEP 3107 & 526 annotations since at least 8 Oct 2019 (see this pull request: https://github.com/hylang/hy/pull/1810)
There is the #^ form as in the example below (from the documentation: https://docs.hylang.org/en/master/api.html?highlight=annotation##^)
; Annotate the variable x as an int (equivalent to `x: int`).
#^int x
; Can annotate with expressions if needed (equivalent to `y: f(x)`).
#^(f x) y
; Annotations with an assignment: each annotation (int, str) covers the term that
; immediately follows.
; Equivalent to: x: int = 1; y = 2; z: str = 3
(setv #^int x 1 y 2 #^str z 3)
; Annotate a as an int, c as an int, and b as a str.
; Equivalent to: def func(a: int, b: str = None, c: int = 1): ...
(defn func [#^int a #^str [b None] #^int [c 1]] ...)
; Function return annotations come before the function name (if it exists)
(defn #^int add1 [#^int x] (+ x 1))
(fn #^int [#^int y] (+ y 2))
and also the extended form annotate macro. There is also the of macro (detailed here https://hyrule.readthedocs.io/en/master/index.html#hyrule.misc.of):

Using guards in Elixir macros

I am working on macro which would take a function and add some additional functionality. Eg.:
This:
defstate this_works(a, b) do
a + b + 1
end
Should be converted to this:
def this_works(a, b) do
IO.puts("LOGGING whatever")
a + b + 1
end
This is what I have so far. Try running this piece of code in iex:
defmodule MyMacro do
defmacro defstate(ast, do: block) do
{fn_atom, _} = Macro.decompose_call(ast)
quote do
def unquote(fn_atom)(var!(a), var!(b)) do
IO.puts("LOGGING")
unquote(block)
end
end
end
end
defmodule Test1 do
import MyMacro
defstate this_works(a, b) do
a + b + 1
end
end
Test.this_works(1, 2)
This works as expected.
Now, this module does not compile:
defmodule Test2 do
import MyMacro
defstate this_fails(a, b)
when 1 < 2
when 2 < 3
when 3 < 4 do
a + b + 1
end
end
The only change is that I added a guard and macro is unable to deal with that.
How can I improve MyMacro.defstate to make it work with a function with any number of guards?
If you inspect fn_atom with the defstate this_fails(a, b) when 1 < 2, you'll see that it's :when instead of :this_fails. This is because of how when expressions are represented in the Elixir AST:
iex(1)> quote do
...(1)> def foo, do: 1
...(1)> end
{:def, [context: Elixir, import: Kernel],
[{:foo, [context: Elixir], Elixir}, [do: 1]]}
iex(2)> quote do
...(2)> def foo when 1 < 2, do: 1
...(2)> end
{:def, [context: Elixir, import: Kernel],
[{:when, [context: Elixir],
[{:foo, [], Elixir}, {:<, [context: Elixir, import: Kernel], [1, 2]}]},
[do: 1]]}
You can fix this using some pattern matching:
defmodule MyMacro do
defmacro defstate(ast, do: block) do
f = case ast do
{:when, _, [{f, _, _} | _]} -> f
{f, _, _} -> f
end
quote do
def unquote(ast) do
IO.puts("LOGGING #{unquote(f)}")
unquote(block)
end
end
end
end
defmodule Test do
import MyMacro
defstate this_works(a, b) do
a + b + 1
end
defstate this_works_too(a, b) when a < 2 do
a + b + 1
end
end
defmodule A do
def main do
IO.inspect Test.this_works(1, 2)
IO.inspect Test.this_works_too(1, 2)
IO.inspect Test.this_works_too(3, 2)
end
end
A.main
Output:
LOGGING this_works
4
LOGGING this_works_too
4
** (FunctionClauseError) no function clause matching in Test.this_works_too/2
The following arguments were given to Test.this_works_too/2:
# 1
3
# 2
2
a.exs:24: Test.this_works_too/2
a.exs:33: A.main/0
(elixir) lib/code.ex:376: Code.require_file/2
(I also changed the unquote after def to make sure the when clause is preserved.)
The call to defstate is expanded at compile time to the things in the quote block from your defmacro. As such, guard expressions will not be applied to the macro call directly, because at compile time, the function you're defining inside is not called.
So you have to grab the :when tuple yourself and add the guards yourself:
defmodule MyMacro do
defmacro defstate({:when, _, [ast, guards]}, do: block) do
{fn_atom, _} = Macro.decompose_call(ast)
quote do
def unquote(fn_atom)(var!(a), var!(b)) when unquote(guards) do
IO.puts("LOGGING")
unquote(block)
end
end
end
end
Note how I match for a {:when, _, [ast, guards]} tuple now.
When you call a macro with a guard, it will put the original ast inside the first item of the arguments list, and the guard expression inside the second item.
Note that you'll still have to define a catch-all macro definition below this one in case you want to use your macro without guard clauses.

How to dynamically create modules with functions

On compilation stage I can easily produce functions with:
defmodule A1 do
defmodule A2 do
Enum.each %{m: 42}, fn {k, v} ->
def unquote(k)(), do: unquote(v)
end
end
end
IO.puts A1.A2.m
#⇒ 42
Also, I can produce modules with functions from within a function call:
defmodule B1 do
def b2! do
defmodule B2 do
# enum is for the sake of future example
Enum.each %{m1: 42}, fn {_k, v} ->
# def b2(), do: unquote(v) WON’T WORK (WHY?), BUT
#v v
def b2(), do: #v
end
end
end
end
B1.b2! # produce a nested module
IO.puts B1.B2.b2 # call a method
#⇒ 42
Now my question is: how can I dynamically produce a module with dynamically created function names, e. g.:
defmodule B1 do
def b2! do
defmodule B2 do
Enum.each %{m1: 42, m2: 3.14}, fn {k, v} ->
#k k
#v v
def unquote(#k)(), do: #v # THIS DOESN’T WORK
end
end
end
end
NB I was able to achieve what I wanted with
defmodule B1 do
def b2! do
defmodule B2 do
Enum.each %{m1: 42, m2: 3.14}, fn {k, v} ->
ast = quote do: def unquote(k)(), do: unquote(v)
Code.eval_quoted(ast, [k: k, v: v], __ENV__)
end
end
end
end
but it seems to be quite hacky.
I believe this happens due to nested macro invocations (def and defmodule are both macros). If you place an unquote there, it unquotes from the top level def:
defmodule B1 do
k = :foo
v = :bar
def b2! do
defmodule B2 do
def unquote(k)(), do: unquote(v)
end
end
end
B1.b2!
IO.inspect B1.B2.foo
prints
:bar
The Module.create/3 recommends using that function to dynamically create modules when the body is an AST. With that, the code becomes much more elegant than the hacky solution using Code.eval_quoted/3:
defmodule B1 do
def b2! do
ast = for {k, v} <- %{m1: 42, m2: 3.14} do
quote do
def unquote(k)(), do: unquote(v)
end
end
Module.create(B1.B2, ast, Macro.Env.location(__ENV__))
end
end
B1.b2!
IO.inspect B1.B2.m1
IO.inspect B1.B2.m2
Output:
42
3.14

Variable associated to "Optimization terminated successfully" in scipy.optimize.fmin_cg?

I am using scipy.optimize.fmin https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.optimize.fmin_cg.html.
What is the variable associated to "Optimization terminated successfully"?
I need it such that I could write something like:
if "optimization not succesful" then "stop the for loop"
Thank you.
Just follow the docs.
You are interested in warnflag (as mentioned by cel in the comments), the 5th element returned, so just index
(0-indexing in python!) the result with result[4] to obtain your value.
The docs also say that some of these are only returned when called with argument full_output=True, so do this.
Simple example:
import numpy as np
args = (2, 3, 7, 8, 9, 10) # parameter values
def f(x, *args):
u, v = x
a, b, c, d, e, f = args
return a*u**2 + b*u*v + c*v**2 + d*u + e*v + f
def gradf(x, *args):
u, v = x
a, b, c, d, e, f = args
gu = 2*a*u + b*v + d # u-component of the gradient
gv = b*u + 2*c*v + e # v-component of the gradient
return np.asarray((gu, gv))
x0 = np.asarray((0, 0)) # Initial guess.
from scipy import optimize
res1 = optimize.fmin_cg(f, x0, fprime=gradf, args=args, full_output=True) # full_output !!!
print(res1[4]) # index 4 !!!

How to replace records with maps in MatchHead of Match Specification?

An Erlang match specification supports the following pattern with record in MatchHead of Match Specification:
#recordName{field1=1, field='$1', _='_'}
This matches all the recordName records from a table which has field1 == 1 and also does an implicit binding of field to be used later in MatchBody.
Is there anything similar with maps?
I tried (apart from Google) the following syntax(es):
% ERROR: * 1: only association operators '=>' are allowed in map construction
#{key:=1, key:='$1', _:='_'}
and
% ERROR: * 1: illegal use of variable '_' in map
#{key=>1, key=>$1', _=>'_'}
Is it possible to do it and the syntax is documented somewhere I could not find? Or, is it a wrong way of thinking about maps replacing records?
TIA
EDIT:
Perhaps it isn't supported yet. Just saw this post.
1> M = #{k1 => 1, k2 => 2, k3 => 3}.
#{k1 => 1,k2 => 2,k3 => 3}
2> #{k1:=1,k2:=V} = M.
#{k1 => 1,k2 => 2,k3 => 3}
3> V.
2
4> %% but you cannot do
4> ets:fun2ms(fun(#{key1:=V, key2:=R}) when V == 1 -> R end).
Error: ets:fun2ms requires fun with single variable or tuple parameter
{error,transform_error}
5>
5> %% while it is possible to do
5> ets:fun2ms(fun({V,R}) when V == 1 -> R end).
[{{'$1','$2'},[{'==','$1',1}],['$2']}]
6> %% or
6> rd(foo,{k1,k2}).
foo
7> ets:fun2ms(fun(#foo{k1=V,k2=R}) when V == 1 -> R end).
[{#foo{k1 = '$1',k2 = '$2'},[{'==','$1',1}],['$2']}]
8> %% or even
8> ets:fun2ms(fun(#foo{k1=1,k2=R}) -> R end).
[{#foo{k1 = 1,k2 = '$1'},[],['$1']}]
9>