How do I pass a variable to a macro and evaluate it before macro execution? - julia

If I have a method
macro doarray(arr)
if in(:head, fieldnames(typeof(arr))) && arr.head == :vect
println("A Vector")
else
throw(ArgumentError("$(arr) should be a vector"))
end
end
it works if I write this
#doarray([x])
or
#doarray([:x])
but the following code rightly does not work, raising the ArgumentError(i.e. ArgumentError: alist should be a vector).
alist = [:x]
#doarray(alist)
How can I make the above to act similarly as #doarray([x])
Motivation:
I have a recursive macro(say mymacro) which takes a vector, operates on the first value and then calls recursively mymacro with the rest of the vector(say rest_vector). I can create rest_vector, print the value correctly(for debugging) but I don't know how to evaluate rest_vector when I feed it to the mymacro again.
EDIT 1:
I'm trying to implement logic programming in Julia, namely MiniKanren. In the Clojure implementation that I am basing this off, the code is such.
(defmacro fresh
[var-vec & clauses]
(if (empty? var-vec)
`(lconj+ ~#clauses)
`(call-fresh (fn [~(first var-vec)]
(fresh [~#(rest var-vec)]
~#clauses)))))
My failing Julia code based on that is below. I apologize if it does not make sense as I am trying to understand macros by implementing it.
macro fresh(varvec, clauses...)
if isempty(varvec.args)
:(lconjplus($(esc(clauses))))
else
varvecrest = varvec.args[2:end]
return quote
fn = $(esc(varvec.args[1])) -> #fresh($(varvecvest), $(esc(clauses)))
callfresh(fn)
end
end
end
The error I get when I run the code #fresh([x, y], ===(x, 42))(you can disregard ===(x, 42) for this discussion)
ERROR: LoadError: LoadError: UndefVarError: varvecvest not defined
The problem line is fn = $(esc(varvec.args[1])) -> #fresh($(varvecvest), $(esc(clauses)))

If I understand your problem correctly it is better to call a function (not a macro) inside a macro that will operate on AST passed to the macro. Here is a simple example how you could do it:
function recarray(arr)
println("head: ", popfirst!(arr.args))
isempty(arr.args) || recarray(arr)
end
macro doarray(arr)
if in(:head, fieldnames(typeof(arr))) && arr.head == :vect
println("A Vector")
recarray(arr)
else
throw(ArgumentError("$(arr) should be a vector"))
end
end
Of course in this example we do not do anything useful. If you specified what exactly you want to achieve then I might suggest something more specific.

Related

How exactly is "interacting with Core.Compiler" undefined in a generated function?

The docs for generated functions at some point say the following:
Some operations that should not be attempted include:
...
Interacting with the contents or methods of Core.Compiler in any way.
What exactly is meant by "interacting" in this context? Is just using things from Core.Compiler from within a generated function undefined behaviour?
My use case is to detect builtin functions from within an IRTools dynamo (which constructs generated functions), but you can refer to the following dummy code (inspired by Cassette.canrecurse), which contains the actual "interactions" I want to perform:
julia> #generated function foo(f, args...)
mod = Core.Compiler.typename(f).module
is_builtin = ((f <: Core.Builtin) && !(mod === Core.Compiler))
if is_builtin
quote
println("$f is builtin")
f(args...)
end
else
:(f(args...))
end
end
foo (generic function with 1 method)
julia> foo(+, 1, 2)
3
julia> foo(Core.tuple, 1, 2)
tuple is builtin
(1, 2)
Which seems to work without problems.

Haskell HDBC.Sqlite3 fetchAllRows

Since I am an absolute Haskell beginner, but determined to conquer it, I am asking for help again.
using:
fetchData2 = do
conn <- connectSqlite3 "dBase.db"
statement <- prepare conn "SELECT * FROM test WHERE id > 0"
execute statement []
results <- fetchAllRows statement
print results
returns:
[[SqlInt64 3,SqlByteString "Newco"],[SqlInt64 4,SqlByteString "Oldco"],[SqlInt64 5,SqlByteString "Mycom"],[SqlInt64 4,SqlByteString "Oldco"],[SqlInt64 5,SqlByteString "Mycom"]]
Is there a clever way to clean this data into Int and [Char], in other words omitting types SqlInt64 and SqlByteString.
You could define a helper:
fetchRowFromSql :: Convertible SqlValue a => Statement -> IO (Maybe [a])
fetchRowFromSql = fmap (fmap (fmap fromSql)) . fetchRow
The implementation looks a bit daunting, but this is just because we need to drill down under the layered functors as you already noted (first IO, then Maybe and lastly []). This returns something that is convertible from a SqlValue. There are a bunch of these defined already. See e.g. the docs. An example (using -XTypeApplications):
fetchRowFromSql #String :: Statement -> IO (Maybe [String])
I should perhaps add that the documentation mentions that fromSql is unsafe. Meaning that if you try to convert a sql value to an incompatible Haskell value the program will halt.

List of function applications in OCaml & OCaml model of evaluation

I'm not too familiar with OCaml's model of evaluation. I'd be grateful if someone could explain why these two lines of code give different results:
List.iter (fun s -> Printf.printf "%s" s) ["a"; "b"; "c"];; (* prints abc *)
List.iter (fun f -> f) [Printf.printf "a"; Printf.printf "b"; Printf.printf "c"];; (* prints cba *)
OCaml is a strict functional programming language: a function's arguments are evaluated as values (and side-effects in the expressions happen) before they are passed to the function (and any side-effects inside the function can happen).
In order to understand your second example, it is best to desugar it a bit:
List.cons
(Printf.printf "a")
(List.cons (Printf.printf "b") (List.cons (Printf.printf "c") []))
When a function is passed several arguments at once—as is the case for all List.cons functions here—the order of evaluation of the arguments is unspecified. This order can differ between the bytecode and the native compiler, for instance. Here, the compiler you used decided to evaluate the first List.cons's second argument first. In doing this, it encountered an application (the second List.cons)
…
In evaluating the arguments of the last List.cons, it printed c. The result was (), which allowed it to build the value [()]. This argument being ready, it now evaluated the other argument of the second List.cons. That made it print b. Finally, since the argument [();()] of the first List.cons was ready, it evaluated the other argument. That made it print a.
As Pascal Cuoq already answered your question, let me just clear up a potential misunderstanding that I take from the question title: Nowhere in your code is a list of functions.
In the first line there is a list of strings, ["a";"b";"c"].
In the second line you have a list with elements such as Printf.printf "a", which are function applications. Their resulting type is unit, also not a function type. (In fact the list is just [();();()].)
An example of a list of funtions would be
[(fun () -> print_string "a"); (fun () -> print_string "b"); (fun () -> ())]

printing string and calling recursive function

I am currently learning sml but I have one question that I can not find an answer for. I have googled but still have not found anything.
This is my code:
fun diamond(n) =
if(n=1) then (
print("*")
) else (
print("*")
diamond(n-1)
)
diamond(5);
That does not work. I want the code to show as many * as number n is and I want to do that with recursion, but I don't understand how to do that.
I get an error when I try to run that code. This is the error:
Standard ML of New Jersey v110.78 [built: Thu Aug 20 19:23:18 2015]
[opening a4_p2.sml] a4_p2.sml:8.5-9.17 Error: operator is not a
function [tycon mismatch] operator: unit in expression:
(print "*") diamond /usr/local/bin/sml: Fatal error -- Uncaught exception Error with 0 raised at
../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
Thank you
You can do side effects in ML by using ';'
It will evaluate whatever is before the ';' and discard its result.
fun diamond(n) =
if(n=1)
then (print "*"; 1)
else (print "*"; diamond(n-1));
diamond(5);
The reason for the error is because ML is a strongly typed language that although you don't need to specify types explicitly, it will infer them based on environmental factors at compile time. For this reason, every evaluation of functions, statements like if else need to evaluate to an unambiguous singular type.
If you were allowed to do the following:
if(n=1)
then 1
else print "*";
then the compiler will get a different typing for the then and else branch respectively.
For the then branch the type would be int -> int whereas the type for the else branch would be int -> unit
Such a dichotomy is not allowed under a strongly typed language.
As you need to evaluate to a singular type, you will understand that ML does not support the execution of a block of instructions as we commonly see in other paradigms which transposed to ML naively would render something like this:
....
if(n=1)
then (print "1"
print "2"
)
else (print "3"
diamond(n-1)
)
...
because what type would the then branch evaluate to? int -> unit? Then what about the other print statement? A statement has to return a singular result(even it be a compound) so that would not make sense. What about int -> unit * unit? No problem with that except that syntactically speaking, you failed to communicate a tuple to the compiler.
For this reason, the following WOULD work:
fun diamond(n) =
if(n=1)
then (print "a", 1) /* A tuple of the type unit * int */
else diamond(n-1);
diamond(5);
As in this case you have a function of type int -> unit * int.
So in order to satisfy the requirement of the paradigm of strongly typed functional programming where we strive for building mechanisms that evaluate to one result-type, we thus need to communicate to the compiler that certain statements are to be executed as instructions and are not to be incorporated under the typing of the function under consideration.
For this reason, you use ';' to communicate to the compiler to simply evaluate that statement and discard its result from being incorporated under the type evaluation of the function.
As far as your actual objective is concerned, following is a better way of writing the function, diamond as type int -> string:
fun diamond(n) =
if(n=1)
then "*"
else "*" ^ diamond(n-1);
print( diamond(5) );
The above way is more for debugging purposes.

Recursive objects in F#?

This snippet of F# code
let rec reformat = new EventHandler(fun _ _ ->
b.TextChanged.RemoveHandler reformat
b |> ScrollParser.rewrite_contents_of_rtb
b.TextChanged.AddHandler reformat
)
b.TextChanged.AddHandler reformat
results in the following warning:
traynote.fs(62,41): warning FS0040: This and other recursive references to the object(s) being defined will be checked for initialization-soundness at runtime through the use of a delayed reference. This is because you are defining one or more recursive objects, rather than recursive functions. This warning may be suppressed by using '#nowarn "40"' or '--nowarn:40'.
Is there a way in which the code can be rewritten to avoid this warning? Or is there no kosher way of having recursive objects in F#?
Your code is a perfectly fine way to construct a recursive object. The compiler emits a warning, because it cannot guarantee that the reference won't be accessed before it is initialized (which would cause a runtime error). However, if you know that EventHandler does not call the provided lambda function during the construction (it does not), then you can safely ignore the warning.
To give an example where the warning actually shows a problem, you can try the following code:
type Evil(f) =
let n = f()
member x.N = n + 1
let rec e = Evil(fun () ->
printfn "%d" (e:Evil).N; 1)
The Evil class takes a function in a constructor and calls it during the construction. As a result, the recursive reference in the lambda function tries to access e before it is set to a value (and you'll get a runtime error). However, especially when working with event handlers, this is not an issue (and you get the warnning when you're using recursive objects correctly).
If you want to get rid of the warning, you can rewrite the code using explicit ref values and using null, but then you'll be in the same danger of a runtime error, just without the warning and with uglier code:
let foo (evt:IEvent<_, _>) =
let eh = ref null
eh := new EventHandler(fun _ _ ->
evt.RemoveHandler(!eh) )
evt.AddHandler(!eh)

Resources