I need to pass the value that I generate in Red/System to Red. I discovered docs but did not find an example of how to use it. Here is my code:
Red []
#system [
data!: alias struct! [
a [integer!]
b [c-string!]
]
data: declare data!
_foo: func [return: [data!]]
[
data/a: 123
data/b: "Hello"
return data
]
]
sqlite: context
[
my-red-block: []; I want to place here: 123 "Hello"
foo: routine [
/local
x [data!]
]
[
x: _foo
; next line do now work
; push my-red-block x/a
]
]
view [button "Select" [sqlite/foo]]
my-red-block here is Red block that I want to fill with data from Red/System part.
https://github.com/meijeru/red.specs-public/blob/master/specs.adoc#routine-type
Intro
Red uses data stack to pass arguments and return the result. Each value on the stack is a boxed structure 4 platform pointers in size and may contain references to external buffers; this means that you need to construct them and push them on a stack, although some primitive Red/System types (like e.g. logic! or integer!) are promoted automatically if you return them.
In your case, however, usage of the stack is not necessary, as you want to allocate values directly in a block. Experience with low-level programming and knowledge of Red/System with Red runtime API are the essential prerequisites for this task. So let's take your example and go through it step by step.
Unpacking
You have a block and you want to append two values to it, 123 and "Hello". Suppose you want to do that from Red/System. For that, we need to write a routine.
list: []
foo: routine [][...]
Inside this routine, you need to get hold of the block referenced by list word. The hard way to do that is to instantiate a symbol and look up the value in global context by its ID:
list: []
foo: routine [
/local
blk [red-block!]
][
blk: as red-block! _context/get-global symbol/make "list"
]
Passing list as an argument would be more reasonable, but I'll keep it as-is for educational purposes.
Now we want to append 123 to this block. There's block/rs-append function that does exactly that, but it accepts a boxed argument. So we need to box 123 ourselves first.
This is how boxed integer looks like; as you can see, it's simply 32-bit 123 value + slot header and padding. We can construct and initialize such structure ourselves:
int: stack/push* ; allocate slot on data stack
int/header: TYPE_INTEGER ; set datatype
int/value: 123 ; set value
Fortunately, Red runtime already covers that with integer/box function that takes a Red/System integer! and returns a boxed red-integer! struct:
integer/box 123
Now we need to append this boxed integer to a block. Intuitively, we can check block.reds definitions and find block/rs-append that matches our requirements:
block/rs-append blk as red-value! integer/box 123
At the end of this step, we have:
list: []
foo: routine [
/local
blk [red-block!]
][
blk: as red-block! _context/get-global symbol/make "list"
block/rs-append blk as red-value! integer/box 123
]
Now we want to append a "Hello" string, but first we need to construct it. Red strings support UTF-8 and use fixed-size internal encoding (1, 2 or 4 bytes per character, depending on the maximum codepoint size); that's a lot of details to get right manually, so the typical way of constructing such string is by converting it from c-string!.
list: []
foo: routine [
/local
blk [red-block!]
str [c-string!]
][
blk: as red-block! _context/get-global symbol/make "list"
block/rs-append blk as red-value! integer/box 123
str: "Hello"
]
Examining string! datatype runtime definitions you will notice some handy wrappers prefixed with load; this is a convention indicating that such function can be used to construct (i.e. "load") high-level Red value from low-level Red/System parts, in our case red-string! from c-string!. Since we want to construct it at the tail of a block, we can use string/load-in:
str: "Hello"
string/load-in str length? str blk UTF-8
Note that I use length? instead of size? to exclude NUL-terminated byte.
Conclusion
This is it. At the end of the day we can tidy the code a little bit and check if it works at all:
Red [Note: "compile in release mode (-r flag)"]
list: []
foo: routine [
/local
blk [red-block!]
int [integer!]
str [c-string!]
][
blk: as red-block! _context/get-global symbol/make "list"
int: 123
str: "Hello"
block/rs-append blk as red-value! integer/box int
string/load-in str length? str blk UTF-8
]
foo
probe list
Compiling this script in release mode and executing the resulting binary from the shell gives us the expected result:
[123 "Hello"]
Needless to say, this all might look quite overwhelming to newcomers: while both Red and Red/System have decent documentation and learning resources, their bridging via runtime interaction is uncharted territory. The reason for that is because the project is evolving and the API is not yet stabilized, so, at the moment, it's not the right time to document it and cast the design decisions in stone. Experienced developers can get their bearings pretty quickly though, but that requires a solid conceptual understanding of Red's evaluation model -- these basics are what you need to master first.
There's also a plethora of library bindings that you can learn from -- judging by the original example, you are trying to make a CRUD View interface on top of SQLite.
Related
Let's say I want to define a series of structs that will be used as parametric types for some other struct later on. For instance, I would like to have something like
abstract type Letter end
struct A <: Letter end
struct B <: Letter end
...etc...
The idea I've had is to define a macro which takes a string of the name of the struct I want to create and defines it as well as some basic methods. I would then execute the macro in a loop for all names and get all my structs defined at compile time. Something like this:
const LETTERS = ["A","B","C","D"]
abstract type Letter end
macro _define_type(ex)
lines = Vector{Expr}()
push!(lines, Meta.parse("export $ex"))
push!(lines, Meta.parse("struct $ex <: Letter end"))
push!(lines, Meta.parse("string(::Type{$ex}) = \"$ex\""))
return Expr(:block,lines...)
end
#_define_type "A"
for ex in LETTERS
#_define_type ex
end
The first way of executing the macro (with a single string) works and does what I want. However, when I execute the macro in a loop it does not. It tells me some variables are declared both as local and global variables.
Can someone explain what is happening? I believe it may be solved by a proper use of esc, but I can't figure out how.
Thanks!
Edit: Thank you all for the amazing responses! Got my code running!
I think this is what you are trying to do:
module MyModule
abstract type Letter end
const LETTERS = ["A", "B", "C", "D"]
for letter in LETTERS
sym = Symbol(letter)
#eval begin
export $sym
struct $sym <: Letter end
Base.string(::Type{$sym}) = $letter
end
end
end
using .MyModule
string(A) # "A"
See the Code Generation section for more details:
https://docs.julialang.org/en/v1/manual/metaprogramming/#Code-Generation
Okay, the problem here is that in Julia for loops introduce a separate, local scope, while struct definitions need to be in the global scope. So your macro fails because it creates struct definitions in the local scope of the for loop.
A way to get around this is to use #eval, to ensure your struct definitions are evaluated in the global scope. In that case, you don't need to create a macro for that, just have a simple loop like this:
abstract type Letter end
const LETTERS = [:A, :B, :C, :D, :E]
for ex in LETTERS
#eval struct $ex <: Letters end
end
You can even put that loop in a function and it will still work. The defined structs can have fields, as #eval covers the entire code block that follows it.
Note that LETTERS must contain symbols rather than strings for this to work correctly. It's easy enough to convert a vector of strings into a vector of symbols using Symbol.(vector_of_strings).
While there are other ways of achieving what you want to do I believe the core issue is understanding the nature of macros. From the docs (emphasis mine):
Macros are necessary because they execute when code is parsed, therefore, macros allow the programmer to generate and include fragments of customized code before the full program is run.
So the macro in your loop does not "see" the values "A", "B", "C" and "D", it sees the expression: ex. To demonstrate this try using #macroexpand:
julia> #macroexpand #_define_type ex
quote
export ex
struct ex <: Main.Letter
#= none:1 =#
end
var"#11#string"(::Main.Type{Main.ex}) = begin
#= none:1 =#
"ex"
end
end
As you can see the actual value of the variable ex does not matter. With this in mind let's look at the actual error you get. You can reproduce it like this:
julia> for ex in ["A"]
struct ex <: Letter
end
end
ERROR: syntax: variable "ex" declared both local and global
Stacktrace:
[1] top-level scope
# REPL[52]:1
You can probably see that this is not what you want, but why this specific error? The reason is that structs are implicitly global while the loop variable is local.
Here is a possible solution that uses a macro that takes a variable number of arguments instead (I also switched to providing the expression directly instead of as a string):
abstract type Letter end
macro _define_types(exprs...)
blocks = map(exprs) do ex
name = string(ex)
quote
export $ex
struct $ex <: Letter end
Base.string(::Type{$ex}) = $name
end
end
Expr(:block, blocks...)
end
#_define_types A
#_define_types B C D
I'm using the matrix extension in my model and I'd like to be able to change the elements of this matrix through the GUI rather than hard coding them. It looks like this at the moment:
extensions [matrix]
globals [test_matrix]
to setup
set test_matrix matrix:from-row-list [[
1
2
3
4
]]
end
But if I try to set the values using the Input function on the GUI I get an error that it 'expected a literal value.'
set test_matrix matrix:from-row-list [[
element1
element2
element3
element4
]]
When you do [ 1 2 3 4 ] in the first section you're creating a list literal, and NetLogo only allows constant values in list literals (numbers, strings, other list literals). See the Lists section of the programming guide for more.
To make a list with non-literal (variable or expression) values use the list primitive:
set test_matrix matrix:from-row-list (list (list
element1
element2
element3
element4
))
See the FAQ entry as well.
I heard/read this term many times, but cannot understand it. The name implies it should "generate a hash function" and I naively imagine it generating a source code in C for example. I looked on web search, here on Stackoverflow, looked into Wikipedia. But cannot find no good definition and no examples.
From Wikipedia:
A perfect hash function for a set S is a hash function that maps
distinct elements in S to a set of integers, with no collisions. A
perfect hash function has many of the same applications as other hash
functions, but with the advantage that no collision resolution has to
be implemented.
If you know your keys in advance, you can construct such a perfect hash function. Programs that do so are called perfect hash function generators.
One example is GNU gperf, which works like you suggested, taking in a list of keys and printing out C source code.
A hash function generator is a tool for finding a hash function meeting certain criteria. Its output can be in any form that unambiguously describes the hash function, usually in the form of source code in some programming language.
Examples
Perfect hash function
Given a set of distinct strings (for example {"banana", "peach", "pineapple", "apple", "microsoft", "pinemicrosoft"}), find a hash function that will map them to distinct integer values. For example:
"banana" => 6
"peach" => 2
"pineapple" => 123
"apple" => 3
"microsoft" => 77
"pinemicrosoft" => 451
There is no restriction on what the hash function may return for an input string that doesn't belong to our predefined set.
Minimal perfect hash function
Similar to above, but the hash values must form a contiguous range.
"banana" => 1
"peach" => 2
"pineapple" => 3
"apple" => 4
"microsoft" => 5
"pinemicrosoft" => 6
The simplest implementation meeting the functional requirements for a minimal perfect hash function is
to store internally a sorted array of the target strings,
look-up the input value in that array and
return its index.
The drawbacks of such an implementation are that it consumes storage and slows down as the size of the target input set grows. So an additional requirement on the hash function is to minimize its size and running time.
Classificator
Given a set of distinct strings grouped into non-overlapping subsets, find a hash function that will map each string to the index of the subset it belongs to.
For example:
any of {"banana", "peach", "apple"} => 1 // fruit
any of {"lion", "zebra", "dog", "eagle"} => 2 // animal
any of {"red", "green", "blue", "white"} => 3 // color
I wanted a list of numbers:
auto nums = iota(0, 5000);
Now nums is of type Result. It cannot be cast to int[], and it cannot be used as a drop-in replacement for int[].
It's not very clear from the docs how to actually use an iota as a range. Am I using the wrong function? What's the way to make a "range" in D?
iota, like many functions in Phobos, is lazy. Result is a promise to give you what you need when you need it but no value is actually computed yet. You can pass it to a foreach statement for example like so:
import std.range: iota;
foreach (i ; iota(0, 5000)) {
writeln(i);
}
You don't need it for a simple foreach though:
foreach (i ; 0..5000) {
writeln(i);
}
That aside, it is hopefully clear that iota is useful by itself. Being lazy also allows for costless chaining of transformations:
/* values are computed only once in writeln */
iota(5).map!(x => x*3).writeln;
// [0, 3, 6, 9, 12]
If you need a "real" list of values use array from std.array to delazify it:
int[] myArray = iota(0, 5000).array;
As a side note, be warned that the word range has a specific meaning in D that isn't "range of numbers" but describes a model of iterators much like generators in python. iota is a range (so an iterator) that produced a range (common meaning) of numbers.
When quoted using quote do: records aren't converted to tuples containing the record fields:
iex(1)> quote do: is_bitstring("blah")
{:is_bitstring, [context: Elixir, import: Kernel], ["blah"]}
iex(2)> quote do: Computer.new("Test")
{{:., [], [{:__aliases__, [alias: false], [:Computer]}, :new]}, [], [[name: "Test"]]}
iex(3)> quote do: Computer.new("Test")
{{:., [], [{:__aliases__, [alias: false], [:Computer]}, :new]}, [], [[name: "Test"]]}
iex(4)> c = Computer.new("Test")
Computer[name: "Test", type: nil, processor: nil, hard_drives: []]
iex(5)> c
Computer[name: "Test", type: nil, processor: nil, hard_drives: []]
iex(6)> quote do: c
{:c, [], Elixir}
Also, when I try doing this in my code:
defmacro computer([do: code]) do
# macro login here
# build computer record based on macro logic
computer = Computer.new(params)
quote do: unquote computer
end
I get an error:
** (CompileError) elixir/test/lib/computer_dsl_test.exs: tuples in quoted expressions must have 2 or 3 items, invalid quoted expression: Computer[name: "", type: nil, processor: nil, hard_drives: []]
I thought that records were just tuples with wrappers functions of some sort. The Elixir Getting Started guide states "A record is simply a tuple where the first element is the record module name." Is there something I am missing? Is there a function I can call on a record to get the tuple representation? I am aware of the raw: true option but I am not sure how to use that on an existing record.
Any insights?
Records are tuples. The output you see on the console is just formatted for easier inspection. You can check that records are tuples if you inspect them with raw: true:
iex(1)> defrecord X, a: 1, b: 2
iex(2)> x = X.new
X[a: 1, b: 2] # This is formatted output. x is really a tuple
iex(3)> IO.inspect x, raw: true
{X, 1, 2}
As can be seen, a record instance is really a tuple. You can also pattern match on it (although I don't recommend this):
iex(4)> {a, b, c} = x
iex(8)> a
X
iex(9)> b
1
iex(10)> c
2
The quote you are mentioning serves completely different purpose. It turns an Elixir expression into AST representation that can be injected into the rest of the AST, most often from the macro. Quote is relevant only in compile time, and as such, it can't even know what is in your variable. So when you say:
quote do: Computer.new("Test")
The result you get is AST representation of the call of the Computer.new function. But the function is not called at this point.
Just reading the error message and the elixir "getting stated" on macro definition it appears that the result of a quote has the form:
In general, each node (tuple) above follows the following format:
{ tuple | atom, list, list | atom }
The first element of the tuple is an atom or another tuple in the same representation;
The second element of the tuple is an list of metadata, it may hold information like the node line number;
The third element of the tuple is either a list of arguments for the function call or an atom. When an atom,
it means the tuple represents a variable.
Besides the node defined above, there are also five Elixir literals that when quoted return themselves (and not a tuple). They are:
:sum #=> Atoms
1.0 #=> Numbers
[1,2] #=> Lists
"binaries" #=> Strings
{key, value} #=> Tuples with two elements
My guess is that the unquote is the reverse function of quote, and so it expects as argument one of the above forms. This is not the case for the computer record.
I think the unquote is not necessary there (although I didn't try to understand the intent of your code...) and that
defmacro computer([do: code]) do %% why do you need this argument?
quote do: Computer.new
end
should be ok.