
is the idea of the tagclass
and nodeclass
DSL to allow people to make their own models and puzzles? or is the DSL you’re making specialized to this arithmetic puzzle?

I definitely want other people to be able to make their own FARG models with this DSL. Another grad student here has occasionally been pair-programming with me on it, hoping to apply it to model that he’s planning to make. Also, there is a neat theoretical idea, where different parts of the graph form coalitions and compete or steal each other’s nodes, which I want to try out. Really, the best way to think of this thing is that it’s a test bench for experimenting with ideas for FARG models—hopefully without writing huge amounts of code. (Past FARG models have been 15,000 lines of Lisp or more.)

Also, I want to model some things aside from this puzzle, especially parsing of natural language and making simple mathematical proofs.

I dunno what I’d do ¯_(ツ)_/¯

Oh well! So, inheritance doesn’t come up often in Racket DSLs?

it sounds like a very complex domain that I have very little experience with so really any advice I can give would be based on generic practices I tend to follow, rather than stuff specialized to your use case

Yeah, I don’t think knowledge of the domain is really necessary. I’m just gunning for how to add inheritance to nodeclasses. Or more generally, how to extract info from syntax objects (like attributes of pattern variables), run it through Racket functions, and then generate code.

A generic principle of mine that might be relevant: if I’m describing something with nouns, I like to reflect that language in code by defining a data type for that noun and then defining a library of operations on that noun. For example, if I’m working with things I’m calling graphs then there ought to be a graph?
predicate and a library of graph-_
functions. So since you’re describing tools to build FARG models, I ask you: what’s a farg-model?
value? What can you do to it? Is there a (farg-model-query model query)
function? A (farg-model ...)
expression that makes a model? If it were me, I’d think about those questions and then create a (require farg-model)
collection with Scribble docs. Any DSLs I make ought to be things built on top of this collection.

so for inheritance and nodeclasses, I’d have to think about what a nodeclass?
object is

no idea if that’s at all helpful to you though

It sounds like we approach this the same way. I’ve got a graph
struct (in the new version now under construction, it’s Graph
since I just moved it to Typed Racket) with a whole bunch of functions to operate on it: making and removing nodes, finding neighbors, etc. Then there’s model.rkt
, which provides a layer on top of graph
. model.rkt
knows about nodeclasses and other elements of the spec. You can tell it to “tag” some nodes, ask it if some nodes have been tagged, ask if a node could be tagged with a certain (not yet created) tag, etc. There are some other things, too, involving a spreading-activation network and a network by which nodes support the continued existence of other nodes.

So, tags

what’s a tag?
value?

Each node has a bunch of attributes: just an arbitrary hash table. The nodeclass determines what those attributes are when the node is first created. If one of those attributes is 'tag?
and its value is #t
, then the node is a tag. The node/tag distinction is mostly how we think about them: tags describe other nodes (including other tags). A node’s nodeclass also determines what it can link to, and its “desiderata”: other elements of the graph that it wants to see built or maintained.

Lexi.lambda led me to an idea earlier today: to make the spec macro generate a “constructor” function for each nodeclass. So, if the spec defined a nodeclass (number n)
, you would get a function number
, that you could call, e.g. (number 17)
, and it would return something—the initial hash table of attributes, I think. That’s very different from the current working version, where I’ve been threading the graph as the first argument through practically every function, and there’s a general make-node
function to which you pass the name of the class and its arguments (e.g. (make-node g 'number 17)
), and it consults the nodeclass struct to figure out how to make the node’s initial attributes.

so this graph has hashes for nodes - what are edges? Are edges between nodes directed or labeled?

Edges in this graph are unordered pairs of (,node ,port-label)
. That is, you don’t simply have an edge between two nodes, you have an edge between specific “ports” of two nodes. For example, a “group” node (a node that “contains” other nodes, like an equation) has a port called members
, and each of its members has a port called member-of
, and there is an edge connecting them.

ah, I get that

I think that’s equivalent to a graph with undirected labeled edges where an edge label is a (pair/c port-label? port-label?)

The spec also has some clauses that provide rules for which ports can link to which other ports. In previous versions, I’ve often had operator nodes, like +
, which have result
and operand
ports. The result
port can link to the source
port of a number; a number’s result
port can link to an operand
port.

Yes.

So, (multigraph/c node? (pair/c port-label? port-label?) #:directed? #f)
in the hypothetical graph API I’ve been meaning to create

I believe so, yes.

I’ve struggled with graph APIs a bunch myself! It’s hard to be fully general without making everything painful.

Strongly agreed

Tags usually have a port called tagged
and link to a port called tags
, but not all tags work that way.

so these nodes, I imagine there’s different node types and that the type determines what ports there are?

Another lesson learned from experience in many programming languages: programming involving graphs is hard! Much harder than it seems like it ought to be.

I’ve played a bit with making a tiny DSL to walk around a graph starting at a given node and collect nodes to operate on and maybe do something to them, but it’s never been satisfactory.

Yeah. I’ve really wanted to see a good immutable graphs library for racket that used the algebraic approach described in this blog post: https://blogs.ncl.ac.uk/andreymokhov/an-algebra-of-graphs/

specifically, there’s an algebra of graphs described by the following components:
- an empty graph
- the overlay operator, which combines two graphs into a single graph with the nodes and edges of each but doesn’t add any edges
- the connect operator, which combines two graphs into a single graph and adds an edge from every node of the left graph to every node of the right graph
- singleton graphs which can be constructed from regular values by turning the value into a one-node graph with no edges

the operators have some nice math properties and they’re a decent way to express how to build up an immutable graph

The graphs in this program are immutable but the API has none of that algebraic elegance. It’s mostly lots of code that looks like this:

There’s got to be a better way to do it, but at least for now, the graph representation is not the pain point. Right now, all the pain is in defining searching and matching—and, for the moment, converting the spec macro to generate Typed Racket.

yup I’d definitely need scribble docs to make more sense of this :p

Oh well, there goes my dream of writing readable, self-explanatory Racket code. :wink:

the most readable Racket code is the code you never have to read because the API docs were enough :P

I’m glad to hear that from someone with experience! I’d been getting that impression.

(don’t worry that’s quite nice code, it’s just there’s lots of concepts involved that I’m totally unfamiliar with)

So, searching and matching

sounds like the domain of a graph-query?
type

Could be. I’ve got some hacked-up, hand-coded stuff that will probably get me to my next demo—if, that is, I can get my spec macro working again, now that I’m moving to Typed Racket.

A lot of the matching should be done by the applies-to
clauses in the nodeclasses. We often just want to ask “If we made a tag of class such-and-such, could it apply to these nodes? Yes? Then build it.”

The current working version has lots of rather bug-prone code that looks at nodeclass
structs (and applies-to
structs and taggee-info
structs and by-ports
structs …) to answer that question. Now that I know syntax-parse
a little better, I’m thinking that the macro should just generate a single function to answer it for each nodeclass. At compile-time, we already have all the information at hand, so hopefully that will be easier—and faster and less bug-prone.

Now that I’ve come to see a little of the enormous power of syntax-parse
, I’m a little surprised that it’s not easy to do something like whip up a compile-time hash table of computed info or sort some doodads topologically for inheritance. Are we missing some easy way to operate on syntax objects?

¯_(ツ)_/¯

There’s probably an easy way to do it but I’m not gonna be able to figure it out at 1AM with a distracted mind

I know what you mean. My brain was out earlier tonight, though miraculously it seems to have woken up again.

I think I’ll experiment some more with the approach of making structs, sorting the structs, and then generating code from the structs. That seems to be what’s hinted at on this page: https://docs.racket-lang.org/syntax/varied-meanings.html

Good idea

I think I’ll mess around with making a total / partial orders library and some graph and multiset APIs

Is there some documentation somewhere that explains how those attributes of pattern variables are stored? That seems to be the main obstacle: the syntax objects don’t actually contain their attributes, is that right?

Right. But I do know you can extract the value of an attribute you know the name of using (attribute foo.attr)

Ohhhh. I didn’t know you could do that. I’d been wondering how you can use attribute
to get at something outside the current syntax class.

Just had a thought: long ago, in Chez Scheme, I did icky stuff in syntax-case
macros by calling syntax->datum
and datum->syntax
all over the place. So, that’s always available as a fallback.

when in doubt, destroy everything but the data inside the syntax object :p

works every time (note: does not actually work every time)

:wink:

Yeah, I remember that code was painfully bug-prone.

OK, here’s something new. I made a new attribute for nodeclass: a struct called sortable
. I put this test code in the “top level” (the syntax-parse
rather than a syntax class), and it makes this error message. How do you apply an ellipsis when you have a non-syntax-object attribute?

ah, you can’t

non-syntax attributes are only useful with the (attribute nc.sortable)
mechanism of extracting the attribute value

in your case the topo
attribute is a list of syntax objects, but it is not itself a syntax object

wait no I misread

ah, now I see what you want

OMG this seems to work:

(attribute nc.sortable)
works even if nc.sortable
is a repeated attribute

yeah like that

it gives you a list of attribute values

This might be the answer!

it works for arbitrary elipses depths too

e.g. if you needed two elipses, then (attribute foo.attr)
would give you a list of lists

Hallelujah! I’ve gotten lots of bruises fighting with syntax-parse
over how many ellipses I need.

“Just gimme a list of lists, will ya??” Well, there it is. :slightly_smiling_face:

finally, the magic easy approach is discovered :p

Is there any way I can get this to work without resorting to (inst ident-class Number)
?

@hoshom I’m still pretty new to Typed Racket, but the example of cons%
on this page makes me think that the inst
is necessary.

@bkovitz I think you’re right

@notjack Well, I got the topological sort to work. It remains to be seen if I can exploit that to actually inherit things while generating code. But now I’m taking a break!

:tada: :tada: :tada:

and for me it’s definitely time for sleep

Hey! I’m trying to update the wrapper for libsodium (the crypto library)

and I’m seeing a consistent issue with the return code being –1

And I’m trying to track down if it’s in the FFI or if it’s in my usage of libsodium

Can someone eyeball this definition for generichash

(define sodium-ffi (ffi-lib "/usr/local/lib/libsodium.so"))
(define-ffi-definer define-sodium sodium-ffi)
(define-sodium crypto_generichash (_fun (output : (_bytes o crypto_generichash_bytes))
(_size = crypto_generichash_bytes)
(input : _bytes)
(_llong = (bytes-length input))
(key : _bytes)
(_size = (if (not key) 0 (bytes-length key))) -> (r : _int) -> (values r output)))

@earl libsodium defines crypto_generichash_bytes
as a function, not a constant, so you need to apply it in the two places it appears above (or use the constant crypto_generichash_BYTES
, if you’ve defined it). But I also recommend looking at the crypto
package, which provides access to much of libsodium, including BLAKE2b (the algorithm implemented by crypto_generichash
).

Hello everyone! I sent a question on SO about a somehow complex macro question: https://stackoverflow.com/questions/55045447/how-to-access-syntax-class-attributes-in-optional-that-contains-ellipsis I found a solution, but I wonder if there’s a better way to do what I’m doing (correctly handling syntax-classes used in ~optional). Do you mind taking a look? :slightly_smiling_face:

@alexknauth Thanks for your awesome answer :slightly_smiling_face:

@ryanc interesting, the lower cased version worked for me but the uppercase version didn’t.

> crypto_generichash_bytes
8376
>

That’s a pretty implausible hash output length. How was crypto_generichash_bytes defined?

(define-sodium crypto_generichash_bytes _int)

You’re right though… that’s weird

The declaration in sodium/crypto_generichash.h
is size_t crypto_generichash_bytes(void);
. So the wrapper should define it as a function: (define-sodium crypto_generichash_bytes (_fun -> _size))
. Defining it with _int
just takes the lower 32 bits of the function’s address.

:+1::+1:

Thank you, that makes sense, I thought it was being exported as a context.

*constant

Cheers!

Just want to be sure. Is kernel-syntax-case/phase stx i ...
equivalent to syntax-parse
with literal-sets being ([kernel-literals #:phase i])
?

@earl I wasn’t sure if you noticed @ryanc had pointed out the crypto
Racket package? https://docs.racket-lang.org/crypto/index.html

Not necessarily to discourage you from making your own wrapper, and perhaps another package. Well… maybe to discourage you a little bit. :smile: I wonder if it’s a domain where we’d all benefit from more eyeballs on one thing. ¯_(ツ)_/¯

@mflatt Is there any reason that Racket’s opengl context (the one for canvas%
) doesn’t use glew at all?

I was asked this and I didn’t really have an answer.

(Basically, the opengl context doesn’t seem to work on windows 64 bit with an intel graphics card)

No reason, other than me not knowing about GLEW

Why does HTML generated by scribble look like the old-timey racket documentation and not the lovely current version?

I guess you are using scribble/base
now and the ‘lovely current version’ you mean probably refers to the style used by current Racket documentation: https://docs.racket-lang.org/index.html Use scribble/manual
to get the same L&F used by Racket Documentation.

actually I’m using scribble/lp2

#lang scribble/manual
@(require scribble/lp2)
may work for you. However, since you just want a better css style, I feel replacing the content of scribble.css
is the best way to do this.