Re: strange (for me) problem with "No matching ctor found for class ..."

2016-05-04 Thread Ben Kovitz
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 ..."

2016-05-04 Thread Ben Kovitz
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 ..."

2016-05-04 Thread Ben Kovitz
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?

2018-01-01 Thread Ben Kovitz
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?

2018-01-01 Thread Ben Kovitz
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?

2018-01-02 Thread Ben Kovitz
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?

2018-01-04 Thread Ben Kovitz
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?

2018-01-04 Thread Ben Kovitz
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?

2018-01-04 Thread Ben Kovitz
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?

2018-01-10 Thread Ben Kovitz
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.