Git Product home page Git Product logo

signals's Introduction

Build Status

purescript-pselm-signals

This is a work-in-progress to provide a Purescript implementation of Elm 0.16's signal-related modules.

For the Elm architecture as implemented in Elm 0.17 and 0.18, see purescript-pselm-core. That is also where I have moved some descriptive text about differences between Elm and Purescript, and the status of the project as a whole.

signals's People

Contributors

rgrempel avatar

Stargazers

Kamil Adam avatar  avatar Dan Minshew avatar Ismael González Trujillo avatar  avatar  avatar Moved to @ad-si avatar Victor Igor avatar Bradley Weston avatar Graham Campbell avatar Kamil Chmielewski avatar Xu Sheng avatar drathier avatar  avatar Quang Van avatar Steve Godin avatar Stefan avatar  avatar Fabian Beuke avatar Gabriel avatar footearth avatar Sergio Diaz avatar Rajiv Bose avatar  avatar Alex Chistyakov avatar Andrey Trofimov avatar William Wolf avatar henryscala avatar  avatar Robert Larnach avatar Tim de Putter avatar Jaremy Creechley avatar Viacheslav Lotsmanov avatar roll avatar Craig Bilner avatar Beeno Tung avatar Anders Nygren avatar Mario Meyrelles avatar Steven Shaw avatar Murph Murphy avatar  avatar Karthik Ravikanti avatar Francis De Brabandere avatar Rob Lucha avatar  avatar Gimi Liang avatar Danny Martini avatar Simon Gardner avatar Arnau Siches avatar Victor Borja avatar Devin Rhode avatar Josh Burgess avatar Tung Dao avatar Josh Miller avatar Yasuhiro Inami avatar Joseph Reutt avatar Elliot Cameron avatar Alexander Thiemann avatar Guido avatar Thomas Weiser avatar 何幻 avatar Vishnu Prasad  avatar Gregory Tod avatar Lukas M. Süss avatar clojj avatar Warren Mira avatar Daniel Garcia avatar Richard Torruellas avatar James Campbell avatar Jeremy W. Sherman avatar Akhilesh Srikanth avatar Dominik Sander avatar Kirill Pertsev avatar Milos Nedeljkovic avatar Jeff Zerger avatar Sudhir Kumar avatar Erik Post avatar Gary Fixler avatar Jón Rúnar Helgason avatar Claudia Doppioslash avatar Irakli Safareli avatar Simon Van Casteren avatar Shaun O'Brien avatar Alex Mingoia avatar Gorgi Kosev avatar Philip avatar jk avatar  avatar Madeline Trotter avatar  avatar Harris Brakmić avatar

Watchers

 avatar Sudhir Kumar avatar Claudia Doppioslash avatar Viacheslav Lotsmanov avatar James Cloos avatar Andrew Condon avatar  avatar Nick Hamilton avatar

signals's Issues

Perhaps divide into multiple libraries

For the moment, I've been essentially converting Elm's core libraries into a single Purescript library (though, of course, with multiple modules). So, if I continued this way, one would eventually install the whole thing at once.

This is, of course, convenient, because it means I can build & test the whole thing together. However, it might be a bit large for a single library -- certainly, the Purescript idiom seems to be much smaller libraries, on the whole. Yet, it would also seem cumbersome to make each module a separate library.

One option might be to divide the whole thing into three or four libraries ... possibly with a base library that depends on all of them, so you can easily install them all if you like. The three or four libraries might look like this:

  • purescript-elm-compat ... for modules like Elm.Maybe, Elm.Result, etc. that are only of any interest for Elm compatibility purposes ... no one without legacy Elm code could possibly be interested.
  • purescript-int53 ... for a module like Elm.Int53 which is actually general-purpose ... it doesn't depend on anything else in Elm, and could be of interest to any Purescript developer. And, I suppose I should rename the module to Data.Int53, since it doesn't really need the Elm namespace.
  • purescript-elm-graphics ... for Elm.Graphics.Element, Elm.Graphics.Collage etc. Now that I'm working on these, I can see that they could conceivably be of some interest to any Purescript developer -- they need not be tightly-linked to the rest of Elm.
  • purescript-elm-main ... for the code (that I mostly haven't written yet) that binds together things like Signals, Tasks and the Graphics modules so that you can easily port the main module in a typical Elm application.
  • purescript-elm-signals ... for Elm.Signal and friends, since they are conceivably of some interest even if you're not using an Elm-style main.

At least, that's one approximation of how things could be divided up -- it will need a little more thought.

The other question is where to put some of the other things (outside Elm's core) which I'll need to port. For instance, elm-html, and probably some other essential Elm libraries. Perhaps purescript-elm-essentials?

Tips for converting Javascript to Purescript

In my README, I've been writing down a few tips for converting from Elm to Purescript.

Lately, I've actually been converting a fair bit of Javascript as well (from the parts of Elm implemented in Javascript). So, I should really start documenting some tips for doing that.

For instance, I have a few ideas about dealing with mutability, and could give some examples. E.g., I'd approach the possibilities in about this order (from most attractive to least attractive):

  1. See if you can trivially rewrite without mutability ... often possible.
  2. See if you can use a fold of some kind to keep some state updated.
  3. Consider using recursion ... sometimes you can recurse in situations that you might otherwise mutate.
  4. If the mutation is purely local (i.e. you mutate, but don't need to keep the mutated state), then consider runST, newSTRef etc.
  5. If the mutation occurs across multiple functions, but the mutation takes place inside a larger operation using those functions that doesn't escape, consider using StateT etc. Talk about how this is sort of similar to generating and using closures.
  6. If the mutation is truly chaotic, and references need to be passed around like spaghetti, then try newRef etc.

There are things that could also probably be said about converting object-oriented Javascript code to Purescript.

Reconsider treatment of Tuples

When converting Elm functions that use Tuple parameters, I've been sometimes converting to Purescript's Data.Tuple, and sometimes to a record type ... e.g. something like { x :: Int, y :: Int} instead of Tuple Int Int.

My reasoning was that there is no syntactic sugar for Tuples in Purescript anyway, so any Elm code using those functions is going to have to change, one way or the other. So, I may as well switch to records in cases where records really make more sense.

However, there is (possibly) a flaw in this reasoning. If I consistently used Data.Tuple, then at least the change would be purely mechanical -- you could imagine automating it, for instance. Whereas that would be harder where I've used a record (the automation tool would have to know what the record fields are called).

So, perhaps I should reconsider and just use Tuples where Elm uses Tuples.

Speak at Unscripted

@paf31 asked me if you might be interested in presenting this at one of our remote Unscripted meetups? I'd also very much like it if you could be on April 9 with @alexmingoia who implemented Elm's architecture in Pux!

Integrate various ReaderT / StateT superstructures into something like Elm.Runtime

In order to match the simplicity of some Elm APIs, I've been using ReaderT and StateT in places like Elm.Signal, Elm.Mouse and Elm.Keyboard.

The way in which this simplifies the API is that some things which would otherwise need to be parameters to multiple functions can be provided once (or, in some cases, generated once), and then consulted by multiple functions without an explicit parameter. (So, the ordinary reason for ReaderT and StateT, I think).

The other way in which this helps is by creating "singletons" for some effectful things that the Elm API re-uses. For instance, the Elm API often has a "base" signal, like Mouse.position, and then some signals mapped from it, like Mouse.x and Mouse.y. The way that the Elm API handles this is by generating all defined signals (if the module was imported at all) at run-time, and then pruning those which were not used (in the sense of not connected to something in the signal graph that generates effects). So, both Mouse.x and Mouse.y can depend on one Mouse.position, because the Mouse.position is actually generated.

It would (I think) be difficult to follow that exact strategy in Purescript (though perhaps not impossible) -- and, in any event, it would be interesting to experiment with an approach that only creates the signals that are desired (so that no pruning stage is needed). One way to do this would be to change the signature of something like Mouse.x to require a Signal MousePosition as a parameter. So, you'd manually create a Mouse.position and then supply that to Mouse.x. However, I'd like to change the Elm APIs as little as possible. So, the alternative is to provide a setupMouse function that takes a callback which runs within a ReaderT that has access to a Signal MousePosition. In this way, the original Elm API can be supported, at the cost of adding a function call to setup the callback. (This works particularly well in Elm.Keyboard, where the common base structures are repeatedly re-used).

I'm looking at Elm.Window now, and realizing that one of the things it needs is the "container" node (possibly the <body>, but not necessarily), which is also needed by Elm.Mouse. So, one really ought to integrate those things ... for instance, by having an Elm.Runtime module that has a ReaderT or StateT that tracks the container node. The idea being that you only need to specify the container node once.

In fact, this integrated superstructure might also be a good place to locate the signal graph, since if you need Elm.Mouse or Elm.Window, then you obviously also need Elm.Signal, so there would be no waste. (There would be little waste in any event in just setting up an empty signal graph). So, we might be able to entirely integrate the setup method from Elm.Signal into an Elm.Runtime. We'd probably still need a separate setupMouse and setupKeyboard function (for the common base signals -- we wouldn't want to generate those more than once, or when not needed), but at least we could integrate some things.

So, I should look at establishing an Elm.Runtime module at some point.

Solicit feedback on DOM.Renderable

I've been working on a type-class and associated functions for providing a kind of high-level interface to multiple ways of constructing a virtual DOM.

https://github.com/rgrempel/purescript-elm/blob/master/src/DOM/Renderable.purs

I've got it to the point where it does what I need, but I have also tried to design it in a way that could be generally useful, as a kind of rendez-vous for multiple DOM-rendering modules. So, it could be broken out as a separate package.

Before doing that, I thought I would solicit some feedback from some folks that have written some modules that might benefit from this sort of thing (e.g. @bodil @paf31 @AppShipIt @garyb @alexmingoia).

If you have time, could you take a look and see what you think? That is:

  • is this useful?
  • is the trickery I'm using legitimate?
  • should the API be different in some way?
  • should the names of things be different in some way?

Any feedback would be much appreciated!

Equatable functions

So, I'm currently doing a little work on equatable functions. I thought I'd jot down a few notes here about motivation and approach.

I should say that I do understand that equatable functions are impossible. That's why they are interesting! No, really, I understand that they are actually impossible.

But I should start with motivation. In the Elm libraries, there are a variety of places, particularly the virtual DOM, where one wants to use a certain kind of laziness. You have a function which you only want to calculate if necessary -- you've got the answer from the previous round, and perhaps it hasn't changed -- perhaps it's the same input, and the same function. Hence, you want to know whether it's the same function!

So, it's not quite like Data.Lazy, because (by itself) Data.Lazy just defers the computation. You can't compare the Data.Lazy to a previous Data.Lazy (except by forcing the computation, which would defeat the purpose).

It's also not quite like memoization, since you only need to remember the most recent application of the function. Also, there are two functions involved here -- the function from the previous round and the function in this round -- and you don't know (without help) whether they are in fact the same function.

Now, the way that Elm deals with this need, in a couple of places, is via reference equality -- that is, it checks whether we're literally dealing with the very same function. One could do this in Purescript as well, of course. However, this leaves us, at least in theory, vulnerable to certain kinds of compiler optimizations. (That is, at least in theory, what we thought would be two references to the very same function might not be). Furthermore, it limits the ways in which we can construct the relevant function -- it really must be the very same function, and thus cannot be returned from another function (which creates a new function each time).

So, can we do better than reference equality? What would that look like?

My main idea is to have a type -- say, EqFn -- which represents a normal function lifted into a context that remembers something about how the function came to be.

Now, to go from Function -> EqFn, one would attach a unique ID to the function. This is basically equivalent to reference equality, but it's all we can do in the case where we're entering the system ... that is, where we don't know anything about how the function was made. One would need to document that, for best results, you should start with functions that are defined at "top-level" -- that is, which are "primitive" functions in some sense -- that is, functions not returned by other functions. AFAIK, there is no way in the type system to insist on that, so it would just be a matter of documentation.

By itself, that is really not much better than reference equality -- we just have a unique ID for the comparison, which is basically equivalent to reference equality. The only advantage so far is that we can arrange matters so that we're not vulnerable to certain kinds of compiler optimization.

However, once we're in the world of EqFn, we can do some interesting things. For instance, we can define a way of composing two EqFn -- that is, the <<< operator -- so that we remember which primitive functions were composed. Then, we can actually compare two EqFn which are the results of composition, even if the composition occurred separately (that is, the two resulting functions are not the very same function).

I've got an initial version of this checked in, with some tests:

https://github.com/rgrempel/purescript-elm/tree/master/src/Data/Function
https://github.com/rgrempel/purescript-elm/blob/master/test/Data/Function/Equatable.purs

Now, that implementation turns out to be too simple in some ways ... I'm working on changes that accommodate additional kinds of manipulation of the EqFn. (In particular, the List Int ends up being too simple a structure for the tag). But it gets across the general idea.

I did Google around a bit, and didn't find anything that was quite like this. Which, of course, may mean that it's very badly misconceived! But, it's been interesting so far.

Tuples in Readme

Hi R
Watching a video of yours just now and its excellent!
Looking at the docs to follow along, i notice your statements about Tuple not having a literal syntax.
I was wondering if you had considered the infix (/) ? Its more elaborate than a comma for sure, but does work largely the same.

Thanks
Alex

Re-exports, generated code and calling from Javascript

I had been using re-exports in cases where the Elm function corresponded exactly to some Purescript function. However, it seems that re-exports don't appear in the generated code (for the purposes of calling things from Javascript) -- see:

purescript/purescript#1888

So, it might be better to actually define the functions, as being equal to the Purescript equivalents. I think I can do this in a way that doesn't actually generate an extra function call at run-time, since I can equate the bare names without parameters in these cases.

The other advantage is that I'd be able to supply the familiar Elm documentation. The disadvantage is that I'd lose the link to the Purescript equivalent in the docs, but I suppose I could add it manually.

Converting Elm syntax to Purescript

I was thinking about the process of converting Elm syntax to Purescript syntax ... all the little stuff, like "data vs. type" and "type vs. type alias" etc.

It occurred to me that there already is a program called elm-format, which re-formats Elm syntax in a standardized way. It appears to construct an AST of the source code, and then "interprets" the AST by outputting text in a standardized format.

I wonder if one could simply add a new target for Purescript? That is, given the AST, there wouldn't appear to be any fundamental problem with simply changing the interpreter to output Purescript syntax rather than Elm syntax.

Plus, I could build in some knowledge about purescript-elm -- for instance, modifying the standard imports to refer to their purescript-elm equivalents, and perhaps ironing out a few other things.

The Purescript code it would produce would often need some changes in order to compile, but it could probably be pretty close.

So, I'll take a more serious look at this once I've got the virtual-dom and HTML stuff working.

Elm 0.17 and 0.18 compatibility

I've been taking a look at what is currently known about Elm 0.17, and thought I'd jot down a few thoughts.

One theme in Elm 0.17 is that the Elm runtime has become more coherently defined, with things like Platform and Program. I was going to have to do some of that conceptual work anyway (since I was going to have to define some kind of monad transformer stack to play the role of a runtime), so I can now follow Elm 0.17's lead (as much as is feasible).

Elm 0.17 now has a Cmd type, which is distinct from the Task type. At first glance, it appears that Cmd roughly corresponds to Purescript's Eff (with some additional wrinkles around feeding messages back into your program architecture), while Task continues to roughly correspond to Purescript's Aff. However, that may turn out to be wrong on further analysis.

Elm 0.17 also now has a Sub type, which is a kind of "subscription" to events. This replaces the concept of a Signal, but appears (at first glance) to have a smaller surface area in terms of an API. That is, you're no longer expected to construct a "signal graph" out of basic tools that could combine things in a variety of ways. Instead, your "subscription" feeds straight into the "start-app" structure (now Html.App), which had previously been just one way of managing a signal graph.

Of course, I'll need to translate the "subscription" idea. However, it might be interesting to also retain the old-fashionedSignal concept from Elm 0.16, if there is a sensible way for that to live alongside the new world. Alternatively, it might be interesting to try to build up some of the features of the old signal API on the subscription type.

Elm 0.17 also now has the concept of a special kind of module, which is an "effects" module. This appears to be a kind of module that can provide "hooks" for the runtime to exploit, related to things like initialization and the subscription / command handling system. This appears to be a way of formalizing some of the "magic" which the runtime used to do when setting up the signal graph (now, for setting up subscriptions and commands, presumably). For translating to Purescript, I would guess (at first glance) that it would be a question of typeclasses and/or monad transformer stacks (i.e. a module might implement a typeclass that allows it to participate in a defined way in what a monad transformer stack does to start up the app structure). But that may turn out to be wrong, on further analysis.

Verbose effects rows for Signals

Just a note to myself that the effects rows for anything related to Signals right now are quite verbose, with a large number of effects. At some point, I should do a sweep through that and make sure that they are all needed, and define a type that will make it less verbose.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.