Re: strange (for me) problem with "No matching ctor found for class ..."
On May 4, 2016, at 2:32 PM, Johannes wrote: > Is there any explanation for this behavior? My understanding is that you can't eval function objects. Whatever you give to eval needs to be code that you could enter into the REPL. You couldn't type #function[user/fn--13335/f--13336] into the REPL and have it evaluate to that function. More to the point, the reader doesn't handle the function object represented by that string. For the same reason, you can't put function objects directly into code generated by macros. That said, I've inadvertently given a function object to eval a few times, and *sometimes* it worked. I don't have an explanation for that. It actually caused me some confusion, because, since it worked the first time I tried it, I concluded with surprise and glee that you *can* eval function objects. But it's not true, at least not reliably. If you want to (reliably) make eval return something containing a function object, you need to give eval an expression containing a symbol or expression that evaluates to that function object—not the function object itself. -- Ben Kovitz http://mypage.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: strange (for me) problem with "No matching ctor found for class ..."
On May 4, 2016, at 5:28 PM, Johannes wrote: > Maybe you are right. But I've deliberately given function objects to eval > often without any problems until I used functions of some special kind. I do > not understand why the behavior for the 2 versions of the function f- I've > shown is different. Oops, I think I missed the main problem: you were passing a pre-evaluated map object directly to eval. What eval really wants is the kind of thing that the reader returns after it reads a string. The reader doesn’t evaluate symbols, like f-. That’s eval’s job. When the reader sees the string f-, it returns the symbol f-. You passed eval the actual function object, not the symbol f-. Eval wants to see the symbol; it will replace it with the object that it evaluates to. In other words, I think you just forgot to quote the expressions that you were passing to eval. Adding the quote, here’s what I get: user=> (def f- (let [v 1 #_=> f (fn [x] v)] f)) #'user/f- user=> (eval '{:d f-}) {:d #function[user/fn--10235/f--10236]} user=> (def f- (let [v 1 #_=> f (fn [x] x)] f)) #'user/f- user=> (eval '{:d f-}) {:d #function[user/fn--10243/f--10244]} -- Ben Kovitz http://mypage.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: strange (for me) problem with "No matching ctor found for class ..."
On May 4, 2016, at 6:08 PM, Johannes wrote: > okay, but why does the following work without quotation? > user> (def f- (let [v 1 > f (fn [x] x)] f)) > ;; => #'user/f- > user> (eval {:d f-}) > ;; => {:d #function[user/fn--14679/f--14680]} > user> > > The problem is that the place in my program where I give the map containing > the function object to eval, the map cannot be quoted. Hmm, I thought I had read “eval doesn’t accept function objects” in a couple places on the Internet, but when I checked this page: http://clojure.org/reference/evaluation I found the sentence "Any object other than those discussed above will evaluate to itself.” So, it appears to be a bug, either in the documentation or in eval. I’m only a Clojure noob, having started four weeks ago. so we’ll both have to wait for a more authoritative explanation from someone more familiar with Clojure internals. The reason I know about this (or thought I did) is because I recently struggled with a similar problem: dynamically supplying a method map to extend a protocol to a record. My solution was to define a top-level dynamically rebindable symbol and refer to it inside the expression passed to eval, something like this (untested code): (def ^:dynamic method-map-holder) (def dynamic-def-record [record-sym fields-vector method-map] (binding [method-map-holder method-map] (eval `(defrecord ~record-sym ~fields-vector)) (eval `(extend ~record-sym ~'my-project.core/MyProtocol method-map-holder The trick is to call binding to put the method-map (containing function objects) into a place where eval can see it. That place is: bound to a top-level symbol, which also appears in the object passed to eval. Note that inside the ` form passed to eval, method-map-holder is not preceded by a tilde. eval will see that exact symbol (qualified by the enclosing namespace). The point of all this is to avoid evaluating the map before passing it to eval. Be aware that the above is an ugly hack, and probably not the best way to do it. I showed my actual code to someone with years of Clojure experience, and he immediately said, “Calling eval is a code smell: there’s almost always a better way to do what you’re trying to do,” and we quickly found a likely way to do what I needed with a macro. However, we did not find a way around temporarily binding the method-map to a dynamically rebindable symbol. -- Ben Kovitz http://mypage.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Port graphs: What would Rich Hickey do?
here—obvious, at least, to Rich Hickey or someone with more Clojure experience. Would you care to smack me on the side of the head with the bit of sense that I'm missing? How could you keep this simple and easy to use? -- Ben Kovitz http://pages.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Port graphs: What would Rich Hickey do?
On Monday, January 1, 2018 at 7:57:11 PM UTC-5, Christopher Small wrote: …you might want to look at Datomic (also authored by Rich Hickey), > DataScript (an in-memory approximation) or RDF (data language of the > Semantic Web). They model graphs as `(entity, attribute, value)` triples, > where `attribute`s can act as labeled, directional arrows between entities, > and can themselves show up in the `entity` position of other triples, thus > allowing you to have "meta-attributes" (attributes pointing to/from other > attributes). Datomic might be just the dose of simplicity I was looking for! I haven't yet used Datomic, so now is probably a very good time to try it out. I had thought that Datomic might make a good underlying implementation rather than the API, but now I wonder if the Datomic API has ideas I could use. The entity-attribute-value approach sounds to me like one of the best ideas ever (long predating computers, even). Thanks! I'll have a closer look. This might even be what Rich Hickey would do! :) Do you need to be able to attach data to specific edges instances? > Yes. Every edge needs to be able to have an arbitrary map of attributes. Or would it be sufficient to be able to have different types of edges, and > be able to associate data with those abstract edge types? > I'd like to be able to treat all edges the same. > This is for a research project, so I need to be able to try out new ideas quickly to see how they perform. I've been using an implementation of port graphs modeled on ubergraph with some success, where all nodes and edges can have arbitrary attribute maps associated with them. Where I've needed edges that link to edges, I've used a couple hacks, like making a separate graph where some of the nodes are edges from the main graph. The nuisance of using those hacks has been steering me away from trying out promising ideas that freely make use of edge-to-edge edges. So, I figure that it's time to just implement this right and be done with it. The fact that it's a research project makes minimal error-proneness especially important. It's often hard to know in advance what the correct behavior looks like. The reason for writing the program is to find out. > Obviously, this is a little bit different from your "ports" idea (I > haven't read about this; is it published on anywhere?), but in some ways a > helpful restriction. > If you google for "port graphs", you'll find some stuff. It's not clear to me why, but port graphs seem to be popular for "graph-rewriting systems" (also googlable). I'm working on something like a graph rewriting system. I hit on the idea as a way to make the graph simpler, and only later found out that there's already a standard name for these graphs and even some good research literature. There's *some* sort of natural fit here. > For example, `mom` vs `child` is isomorphic to an edge labeled > `isMotherOf`. But simpler, because there's less to specify, and in > particular, less to get wrong with respect to which kinds of ports can > connect to which kinds of other ports. > Something I've liked about the port graphs up until now is that it's easy to add an explicit representation of rules for which kinds of ports can connect and which can't. The current implementation (the one without edge-to-edge edges) has some "shorthand" functions that exploit those rules so that you can specify some edges very simply, often without explicitly providing the port labels, since the system can (in some cases) deduce them. Most of my previous experiences with programming involving graphs have involved a lot of hard-to-read code and a lot of sweating and gritting my teeth while trying to avoid bugs. The ports-rules-and-shorthand approach has enabled to me keep the code mostly readable. In fact, much of the code is just static data that specifies small subgraphs—in a pretty readable way. The rules are also nicely separable from the generic aspects of the graph. I added a couple protocols beyond the loom protocols: one for creating new nodes of a given 'class', so they can get ids and attributes assigned to them automatically; and one for consulting the rules for legal connections. But it's clearly time for me to look at this in a new way. I like your observation that (in effect) edge classes of the form (port-label1, port-label2) are isomorphic to edges between ports. That and Datomic might be exactly the whack(s) on the side of the head that I needed! -- Ben Kovitz http://pages.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are
Re: Port graphs: What would Rich Hickey do?
Christopher Small, Your suggestion to look into Datomic definitely turned up a new idea. I went through the Datalog tutorial at http://www.learndatalogtoday.org (which is excellent, by the way), and noticed that the attribute names in the datoms are a lot like the port labels in port graphs. A port label is essentially an attribute key whose value is the edges incident to it. And when you chain data patterns in Datalog queries, that's a lot like navigating through a graph. The new, hopefully simple, easy-to-use, and not error-prone idea is to use the clojure.lang.IPersistentMap interface to query and update graphs. Nodes, edge, attribute names, port labels, and a few "reserved keywords" like :adj-nodes and :edge, could navigate the graph as if it were an ordinary nested map with get-in, assoc-in, and the like, without ever needing to wrap anything inside a record to tell what it is. Here are some sample queries and what they could return: (get-in g [node port-label :adj-nodes]) a coll of all the nodes with an edge to [node port-label] (get-in g [node port-label :adj-node]) one node with an edge to [node port-label], or nil (get-in g [node port-label]) true or false, according to whether node has a port named port-label (get-in g [node k]) value of node's attr k (get-in g [edge k]) value of edge's attr k (get g node-or-edge) the entire map of attrs associated with node-or-edge, or nil if it does not exist (get-in g [node k1 k2 k3]) treat node's attrs as a nested map (get-in [node port-label :edges]) a coll of all the edges that link to [node port-label] (get-in [node port-label :edge]) a single edge that links to port-label, or nil (get-in [node port-label1 port-label2]) coll of all nodes that link to [node port-label1] from a port named port-label2 And here are some function calls that would return a modified graph: (assoc-in g [node k] v) sets node attr k to v (assoc-in g [edge k] v) sets edge attr k to v (and similarly for multiple keys) (assoc-in g [node1 port-label1 port-label2 node2] :edge) makes an edge between [node1 port-label1] and [node2 port-label2] (assoc-in g [node1 port-label1 port-label2 :edge k] v) sets value of edge attr k to v I haven't yet thought this through completely, and I suspect that some parts are still error-prone. For example, notice in the last function call that it's not clear whether you should include node2. The approach might be "too cute"—that is, brittle because it tries to impose one kind of structure (nested maps) onto one that isn't fully isomorphic (graphs). But I like the basic idea of having a "little language" for designating whatever you want, and the little language is nothing but a sequence that tells how to navigate through the graph to find (or make) what you're interested in. This would solve the fundamental problem of how to designate an edge without imposing type restrictions. For each connection point, you just have a sequence that describes a path to that point. If the sequence ends on a port label, the connection point is a port. If it ends on :edge, the connection point is an edge. So, instead of type restrictions, there are just a few reserved words in the tiny DSL for navigating the graph. This hopefully makes simple editing and querying of port graphs easy, but it does not even try to solve the problem of conveniently entering a graph. I figure that a "shorthand", i.e. a separate tiny DSL, is the solution for that. I found with my current implementation of port graphs that it really helped to use a custom shorthand for each specific type of graph. For example, there's a obvious and very nice shorthand for specifying graphs that represent mathematical expressions, but it's terrible for graphs of social networks. Graphs of social networks, though, can be conveniently described by their own custom sexprs. I figure that implementing it will force me to think this idea through the rest of the way. Here goes… -- Ben Kovitz http://pages.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Port graphs: What would Rich Hickey do?
On Tuesday, January 2, 2018 at 3:11:45 PM UTC-5, Christopher Small wrote: > http://docs.datomic.com/entities.html > > http://docs.datomic.com/pull.html > Thanks—this is really good stuff! Not that I expected anything less, but it's a happy surprise that it applies so well to graphs. Now I'm wondering if I should just use Datomic rather than borrow ideas from it. One thing I'm convinced of now is that it's OK to assign ids to everything. I was cringing at that idea before, because it seems like an unnecessary layer of indirection and one more thing that could go wrong. But clearly Datomic's approach of assigning every "entity" an id enables some wonderful simplicity, since it enables one to very conveniently chain entities together. And when basically everything is an entity, that means you can chain anything to anything—which addresses the "type headache" I was trying to avoid. -- Ben Kovitz http://pages.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Port graphs: What would Rich Hickey do?
On Thursday, January 4, 2018 at 4:01:41 AM UTC-5, Gary Verhaegen wrote: Have you considered encoding your port graph into a normal graph? That was the first idea I had, and I quickly rejected it as adding complication. The consideration that led me to port graphs in the first place was that when, say, I have a node for "plus", and it has neighbor nodes for "operand" and "sum", which other nodes connect to, an easy bug is that when the "plus" is deleted, its "operand" and "sum" nodes might not get deleted—leaving the graph in an invalid state. I figured it would be best to just absorb those connection nodes into the "plus" node in the form of a list of "ports", and include the port labels in the edges. Then deleting the "plus" automatically deletes the ports, you can easily query for "what nodes are connected to the plus" (where you want to skip connection nodes), and generally there are fewer ways to make mistakes in the code. However, following Christopher Small's suggestion to check out the Datomic APIs, I'm now thinking that a layer to map the port graphs to simplicial ("normal", undirected) graphs might actually be the simplest thing. Nodes, ports, and edges are easily represented by nodes in a simplicial graph. This escapes the "type headache" that led me to start this thread, since all edges in the port graph are just plain nodes in the simplicial graph, whether they're port-to-port edges, port-to-edge edges, or edge-to-edge edges. The layer of indirection might cost some performance—and performance does matter here, since this program is extremely CPU-bound—but it's more important to preëmpt bugs by keeping code simple. And now you make this interesting point, which I hadn't previously considered: That would require you to define a mapping, but would then allow you to > fairly easily reuse theorems, algorithms and libraries by having them > operate on the encoded graph, with a hopefully thin layer of translation. I could even use ubergraph to represent the simplicial graph, and thereby get access to all code that follows the loom protocols. I have seen this approach of encoding graphs into other graphs work out > pretty well in other contexts. Do you remember any of those other contexts? Maybe I could check one out and learn something from it. If you’re shopping around for ideas as to how to define data manipulation > API, it may be worth taking some time looking at Specter too. > Thanks for this suggestion, too. I'm now checking it out. -- Ben Kovitz http://pages.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Port graphs: What would Rich Hickey do?
I replied to Gary Verhaegen: If you’re shopping around for ideas as to how to define data manipulation >> API, it may be worth taking some time looking at Specter too. >> > > Thanks for this suggestion, too. I'm now checking it out. > Well! So far, Specter appears to have taken the "path map" idea that I'd been toying with to its ultimate logical conclusion—far better than I could ever do it. Nathan Marz even says that needing to manipulate tricky graphs "forced" him to come up with Specter. If I understand it correctly, Specter would even allow me to map these peculiar port graphs to simplicial graphs without adding any performance overhead. It looks like I'd need to write a custom navigator or two. I haven't yet found a good tutorial for getting beyond the most elementary concepts of Specter, though. Can you recommend one? -- Ben Kovitz http://pages.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: Port graphs: What would Rich Hickey do?
On Monday, January 8, 2018 at 12:14:59 AM UTC-5, James Gatannah wrote: > FWIW, I think https://leanpub.com/specter looks extremely interesting. > (Or it may be awful...I haven't had a chance to read it yet, much less work > through the exercises). > Actually, I worked through that ebook last week. (Or at least the version of the ebook in Google's cache. Leanpub's web site appears to be down.) It's excellent! It didn't go all that far, but it got across the main ideas very effectively. I've been continuing to look at Specter, and the more I've learned, the better it's seemed. I have yet to try it myself on anything beyond toy examples, though. Currently I'm stumped on how to make a navigator for a data structure that doesn't work with 'get' and 'assoc'. There's probably still something elementary that I haven't understood yet. I just posted a question on the github site: https://github.com/nathanmarz/specter/issues/241 -- Ben Kovitz http://pages.iu.edu/~bkovitz/ -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.