notjack
2019-3-7 08:00:52

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?


bkovitz
2019-3-7 08:03:57

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.)


bkovitz
2019-3-7 08:05:06

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


notjack
2019-3-7 08:06:09

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


bkovitz
2019-3-7 08:06:30

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


notjack
2019-3-7 08:06:45

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


bkovitz
2019-3-7 08:08:23

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.


notjack
2019-3-7 08:13:40

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.


notjack
2019-3-7 08:14:12

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


notjack
2019-3-7 08:15:10

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


bkovitz
2019-3-7 08:20:08

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.


notjack
2019-3-7 08:20:51

So, tags


notjack
2019-3-7 08:21:01

what’s a tag? value?


bkovitz
2019-3-7 08:24:46

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.


bkovitz
2019-3-7 08:28:27

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.


notjack
2019-3-7 08:28:55

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


bkovitz
2019-3-7 08:31:19

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.


notjack
2019-3-7 08:32:49

ah, I get that


notjack
2019-3-7 08:33:32

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


bkovitz
2019-3-7 08:33:53

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.


bkovitz
2019-3-7 08:34:10

Yes.


notjack
2019-3-7 08:35:17

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


bkovitz
2019-3-7 08:35:36

I believe so, yes.


bkovitz
2019-3-7 08:36:09

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


notjack
2019-3-7 08:37:04

Strongly agreed


bkovitz
2019-3-7 08:37:19

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


notjack
2019-3-7 08:38:04

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


bkovitz
2019-3-7 08:38:22

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


bkovitz
2019-3-7 08:39:09

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.


notjack
2019-3-7 08:39:12

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/


notjack
2019-3-7 08:41:30

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

notjack
2019-3-7 08:42:11

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


bkovitz
2019-3-7 08:45:36

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:


bkovitz
2019-3-7 08:48:02

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.


notjack
2019-3-7 08:48:13

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


bkovitz
2019-3-7 08:48:38

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


notjack
2019-3-7 08:49:00

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


bkovitz
2019-3-7 08:49:21

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


notjack
2019-3-7 08:49:34

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


notjack
2019-3-7 08:50:07

So, searching and matching


notjack
2019-3-7 08:50:20

sounds like the domain of a graph-query? type


bkovitz
2019-3-7 08:51:16

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.


bkovitz
2019-3-7 08:52:36

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.”


bkovitz
2019-3-7 08:55:40

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.


bkovitz
2019-3-7 08:57:12

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?


notjack
2019-3-7 09:03:16

¯_(ツ)_/¯


notjack
2019-3-7 09:04:12

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


bkovitz
2019-3-7 09:04:43

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


bkovitz
2019-3-7 09:06:10

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


notjack
2019-3-7 09:06:41

Good idea


notjack
2019-3-7 09:07:10

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


bkovitz
2019-3-7 09:07:41

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?


notjack
2019-3-7 09:08:23

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


bkovitz
2019-3-7 09:09:35

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.


bkovitz
2019-3-7 09:11:09

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.


notjack
2019-3-7 09:12:38

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


notjack
2019-3-7 09:12:56

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


bkovitz
2019-3-7 09:13:49

:wink:


bkovitz
2019-3-7 09:14:18

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


bkovitz
2019-3-7 09:21:28

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?


notjack
2019-3-7 09:24:54

ah, you can’t


notjack
2019-3-7 09:25:16

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


notjack
2019-3-7 09:26:00

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


notjack
2019-3-7 09:26:25

wait no I misread


notjack
2019-3-7 09:26:37

ah, now I see what you want


bkovitz
2019-3-7 09:26:52

OMG this seems to work:


notjack
2019-3-7 09:26:58

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


notjack
2019-3-7 09:27:00

yeah like that


notjack
2019-3-7 09:27:08

it gives you a list of attribute values


bkovitz
2019-3-7 09:27:17

This might be the answer!


notjack
2019-3-7 09:27:31

it works for arbitrary elipses depths too


notjack
2019-3-7 09:27:48

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


bkovitz
2019-3-7 09:28:15

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


bkovitz
2019-3-7 09:28:39

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


notjack
2019-3-7 09:29:16

finally, the magic easy approach is discovered :p


hoshom
2019-3-7 09:36:55

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


bkovitz
2019-3-7 09:48:42

@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.


hoshom
2019-3-7 10:06:56

@bkovitz I think you’re right


bkovitz
2019-3-7 10:08:49

@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!


notjack
2019-3-7 10:10:40

:tada: :tada: :tada:


notjack
2019-3-7 10:10:51

and for me it’s definitely time for sleep


earl
2019-3-7 11:57:26

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


earl
2019-3-7 11:57:37

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


earl
2019-3-7 11:57:54

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


earl
2019-3-7 11:58:01

Can someone eyeball this definition for generichash


earl
2019-3-7 11:58:23
(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)))

ryanc
2019-3-7 14:19:25

@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).


jerome.martin.dev
2019-3-7 14:36:50

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:


jerome.martin.dev
2019-3-7 15:29:27

@alexknauth Thanks for your awesome answer :slightly_smiling_face:


earl
2019-3-7 16:06:22

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


earl
2019-3-7 16:06:27
> crypto_generichash_bytes
8376
>

ryanc
2019-3-7 16:08:38

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


earl
2019-3-7 17:02:07

(define-sodium crypto_generichash_bytes _int)


earl
2019-3-7 17:03:54

You’re right though… that’s weird


ryanc
2019-3-7 17:06:54

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.


earl
2019-3-7 17:08:02

:+1::+1:


earl
2019-3-7 17:08:13

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


earl
2019-3-7 17:08:16

*constant


earl
2019-3-7 17:08:23

Cheers!


sorawee
2019-3-7 18:31:44

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


greg
2019-3-7 18:33:37

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


greg
2019-3-7 18:35:08

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. ¯_(ツ)_/¯


leif
2019-3-7 19:29:05

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


leif
2019-3-7 19:29:27

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


leif
2019-3-7 19:30:04

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


mflatt
2019-3-7 20:33:44

No reason, other than me not knowing about GLEW


matias
2019-3-8 01:00:47

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


oldsin
2019-3-8 02:47:13

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.


matias
2019-3-8 03:22:30

actually I’m using scribble/lp2


oldsin
2019-3-8 03:40:28
#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.