amharrison / jactr

-old - jACT-R Bundles
http://jact-r.org/
7 stars 5 forks source link

Use a fluent interface as an alternative to the io system #24

Open monochromata opened 8 years ago

monochromata commented 8 years ago

This issue competes with #8, only one of them should be implemented.

I just refactored the jactr tests: I split the org.jactr.tests projects and put the tests into the artifacts that they actually test. Because the tests in core did depend on io and io is not a dependency of core (and should not be, to avoid a circular dependency), I rewrote the core tests to create models as POJOs instead of reading them via io. The creation is a bit verbose, so I thought a fluent interface (https://en.wikipedia.org/wiki/Fluent_interface http://www.martinfowler.com/bliki/FluentInterface.html) might help. This API might actually replace #8.

A short example that creates a chunk type, a chunk and a production (incl. references to the chunk type and the chunk).

FluentModel fluentModel = new FluentModel("my-model");
IChunkType myType = fluentModel.chunkType("my-type")
    .slot("first")
    .slot("last").equals(0.0)
    .getChunkType();

IChunk myChunk = fluentModel.chunk("my-chunk").type(myType)
    .slot("first").equals(1.0)
    .slot("last").equals(2.0)
    .getChunk();

fluentModel.production("first")
    .conditions()
        .match("goal")
            .type(myType)
            .slot("first").equals(myChunk)
            .slot("last").equals("=num1")
    .actions()
        .modify("goal")
            .set("first").to("=num1")
        .remove("retrieval")
        .output("Hello =num1");

System.out.println("Created model "+fluentModel.getModel());

It might be possible to refer to chunk types and chunk by reference (i.e. passing the instances as method arguments) or by name (passing the chunk names as method arguments so that the fluent interface needs to look up the previously created chunk (type) by its name).

There a number of points:

What do you think?

amharrison commented 8 years ago

Will address this more fully when I return from work travel. As much as I like fluent interfaces ( and it would be nice to have regardless), I vastly prefer the AST and DSL route as it allows easier and more general tooling, compilation tool chain, static analyzes to boot.

The original intent was to not force the building of models in Java code. Modelers should just focus on modeling, not language dependent coding.

And holy shit, cleaning up the testing package.. Wow. Rock star.

On Mar 28, 2016, at 1:04 PM, monochromata notifications@github.com wrote:

This issue competes with #8, only one of them should be implemented.

I just refactored the jactr tests: I split the org.jactr.tests projects and put the tests into the artifacts that they actually test. Because the tests in core did depend on io and io is not a dependency of core (and should not be, to avoid a circular dependency), I rewrote the core tests to create models as POJOs instead of reading them via io. The creation is a bit verbose, so I thought a fluent interface (https://en.wikipedia.org/wiki/Fluent_interface http://www.martinfowler.com/bliki/FluentInterface.html) might help. This API might actually replace #8.

A short example that creates a chunk type, a chunk and a production (incl. references to the chunk type and the chunk).

FluentModel fluentModel = new FluentModel("my-model"); IChunkType myType = fluentModel.chunkType("my-type") .slot("first") .slot("last").equals(0.0) .getChunkType();

IChunk myChunk = fluentModel.chunk("my-chunk").type(myType) .slot("first").equals(1.0) .slot("last").equals(2.0) .getChunk();

fluentModel.production("first") .conditions() .match("goal") .type(myType) .slot("first").equals(myChunk) .slot("last").equals("=num1") .actions() .modify("goal") .set("first").to("=num1") .remove("retrieval") .output("Hello =num1");

System.out.println("Created model "+fluentModel.getModel());

It might be possible to refer to chunk types and chunk by reference (i.e. passing the instances as method arguments) or by name (passing the chunk names as method arguments so that the fluent interface needs to look up the previously created chunk (type) by its name).

There a number of points:

Using a Java classes to create models will require compilation before a model run. This is not problematic when developing models in Eclipse. It might also be possible to use the fluent interface from BeanShell or JavaScript. The fluent interface might be designed in a way that permits re-use of redundant aspects of productions. E.g. conditions or actions that are identical for different productions might be extracted as a method. Using Java classes will provide out-of-the-box code completion if the fluent interface is based on method chaining only (i.e. if it does not use static methods whose results are passed as parameters: such static methods could not be hinted at by auto-completion). The jactr-eclipse launching infrastructure would need to be adapted to be able to create launch configurations for jACT-R models. Is it possible to show a "Run as ... > jACT-R model" context menu entry for Java classes that implement e.g. a ModelFactory interface? How to do it for BeanShell/JavaScript files? One of the trickier parts will be to design the fluent interface as a state machine because e.g. chunkType(...) needs to invoke dm.createChunkType(...) in the beginning, but also dm.addChunkType(ct) in the end and one will not want to have users of the fluent interface to do final .addToDM() since most will forget that invocation (including me) During the construction of the interface we will need to consider https://en.wikipedia.org/wiki/Fluent_interface#Problems How to replace the ASTParticipants and (in my repository) io/src/main/java/org/jactr/io/include/*.jactr? (I.e. how can third-party modules contribute stuff like chunks, chunk types and buffer (configurations) to a model, potentially before the user of the fluent interface relies on them?) What do you think?

— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub

monochromata commented 8 years ago

Hm, ok, I'm still not sure whether I'd prefer programmatic construction of models over the IO way for my own modelling. But I see that e.g. the Eclipse editor code completion might have a number of Java-specific entries that users without prior exposition to Java might find confusing.

I started creating a fluent interface anyways (https://github.com/monochromata/jactr/commit/18a5852fab2fa3a5ceca239c163058842db9f838), because it eased writing the core tests. It is only able to create productions and does not cover all features that the IO module covers. Already now the fluent interface allows reduced redudancy in test code e.g. by modifying the model construction code inherited from a super-class.

As of now the fluent interface is just there to ease testing. It might be completed to be an alternative to the IO system or a future xtext-based IO system.

amharrison commented 8 years ago

I'm totally on board with having a fluent interface parallel to the IO. Your work so far has been on making the architecture more programmer friendly; this is just a continuation of that. Anything that makes it easier for a wider community to exploit.

I see the fluent api being optimal for simple tests (I loathe building test models in IO myself), or more code oriented folks. If we do it right, there will be no differences in launching or runtime tooling.

I can see modifying the fluent api to have

public FluentModel(Class<? extends IDeclarativeModule> decM, Class<? extends IProceduralModule> procM)

With an empty constructor defaulting to the usual suspects. Similarly, we'd need to include other modules and extensions

.... use(Class<? extends IModule> module) .... use(Class<? extends IExtension> extension)

amharrison commented 8 years ago

I'm looking at org.jactr.embed (in org.jactr.tools), and I'm starting to think two things:

  1. org.jactr.embed needs to be in org.jactr (duh)
  2. fluent should probably be under embed. The two will be used together routinely.
amharrison commented 8 years ago

You may also want to look at org.jactr.tools.misc.ChunkUtilities for current best practices for creating, configuring, & encoding chunks

monochromata commented 8 years ago

org.jactr.core.slot.SlotBuilder is an existing related class.