Qqwy

Qqwy

TypeCheck Core Team

Hey all,

This is a small and simple library I am developing, that will be part in a larger whole of libraries to hopefully at some point allow nice, functional native Graphical User Interfaces to be made from within elixir.

People who know about Elm: This is basically what Elm does as well.


GenFRP

Github, Hex

GenFRP is a library that allows for programming in elixir using the
Functional Reactive Programming method.

This is a way to store and dispatch information that is very readable and extensible.

The idea is as follows:

  1. Your FRP module contains use GenFRP, initial_state: some_useful_starting_state. (some_useful_starting_state can be anything you wish, of course)
  2. It implements the update(state, event) :: state function.
  3. It implements the render(state, last_rendered_state) :: any function.

update is called whenever an event is sent to the GenFRP process by using GenFRP.send_event(frp_pid, whatever_you_want_to_send).

render is called whenever you want to know its current state (in some representation format that is useful for the outside world, i.e. rendered).
GenFRP uses a very simple caching mechanism to ensure that render is only invoked when the internal state has changed since its last invocation.

Here is a very simple example (which can be found as GenFRP.Example.Map as well)

defmodule GenFRP.Example.Map do
  use GenFRP, initial_state: %{}


  def update(state, [{key, val}]) do
    Map.put(state, key, val)
  end

  def update(state, event) do
    IO.puts "Unrecognized event passed to `#{inspect(__MODULE__)}.update/2`: #{event}"
  end
  
  @doc """
  Returns the key-value pairs as strings, separated over multiple lines, in alphabetical order.
  """
  def render(state, last_rendered_state) do
  Enum.map(state, fn {key, val} ->
      "`#{key}`: `#{val}`"
    end)
  end
  Enum.join("\n")
end

This can be used as follows:

    {:ok, pid} = GenFRP.start_link(GenFRP.Example.Map)
    # ... maybe some other code here...
    GenFRP.send_event(pid, {:foo, :bar})
    # ... maybe some more code here...
    GenFRP.send_event(pid, {:baz, 42})
    # ... maybe yet some other code here...
    GenFRP.render(pid)
    "`foo`: `bar`
    ``baz`: `42`
    "

This is the first, 0.1.0 version release. I wanted to get this out quickly, to get some feedback from the community.
Expect things to be still somewhat unfinished, and don’t worry: I will run Credo on the code to make it nicer :stuck_out_tongue_winking_eye:.

But: any feedback is greatly appreciated. Is this programming interface understandable? Are there things that the library is glaringly lacking?

Thank you,

~Qqwy

Showing Posts 1 to 10

michalmuskala

michalmuskala

I don’t see a link to the repo, I think you missed it :smiley:

Looking at the example, I’m not sure I understand the decision to pass the initial state to the use macro. Wouldn’t it be better to follow the example of all the OTP behaviours and have an init/1 callback for computing the initial state? It doesn’t require the initial state to be a compile-time constant, like the current solution does.

Qqwy

Qqwy OP

TypeCheck Core Team

Good catch :sweat_smile:!
Links to the repository and the Hex page have been added.

I think you are right. I am not at all sure why I used the option-based approach; this was not an intentional decision as far as I can remember.
There should not be a restriction on the initial state having to be a compile-time constant, and being able to optionally pass some information at initialization is something that would also be nice.
I will definitely alter this behaviour in the next version.

bobbypriambodo

bobbypriambodo

Hmm, the Github link both on your post and hex page seems broken. It returns 404 for me. Is it still private?

Btw I think this is neat. FRP model such as in Elm and Redux is a nice way to solve some problems. Looking forward to using this in the future if a problem demands it.

OvermindDL1

OvermindDL1

This could be used as the basis to make an elm’y clone in ElixirScript for both server-driven and client-driven page handling. ^.^

Now if only a type system. ^.^

Qqwy

Qqwy OP

TypeCheck Core Team

Yes, it was… (I need to get some sleep).

Yup, that would be amazing. I’m not sure how far ElixirScript is right now with supporting processes; there were some caveats earlier if I remember correctly, but yes, I am sold on this idea :slight_smile: .


As for the native GUI idea: I’m now working on a semi-direct (and thus stateful) wrapper to :wx_widgets called Wex (which is far from finished, because :wx_widgets is HUGE, and there are some design choices that still need to be made). Another to-be-written library that has the WIP-name Candlelight will wrap Wex with its own structs that are stateless representations of a certain GUI. Candlelight will use MapDiff to check for changes in theis GUI representation, and run the required Wex functions to update the changes.

To the end user, this means that a GUI can be constructed and altered by nesting the Candlelight structs (or functions/macros(?) that create them) in a very simple and clear manner.
Very similar to how Elm allows the creation of HTML content using its HTML DSL. However, GUI elements in WxWidgets are a lot more complicated than a HTML representation (which is just ‘text’; we let the browser figure out how it should look) so there is a lot of work to be done :grin: .

uranther

uranther

What is your motivation for creating Candlelight? Plan on making a native GUI app soon with Elixir?

GenFRP looks cool. Looking forward to future releases (and documentation and examples)! Great work!

Qqwy

Qqwy OP

TypeCheck Core Team

There have been multiple ideas floating around here at the company that would work better with a simple native client than by wrapping Phoenix and interfacing through a local port with the application. So while it is not ‘soon’, Candlelight is made with a practical use in mind, yes.

StefanHoutzager

StefanHoutzager

Nice! I don’t know about frp, so I’m reading about it now. Maybe interesting for others also

FRP is about "datatypes that represent a value 'over time' ". Conventional imperative programming
captures these dynamic values only indirectly, through state and mutations. 

Here is a short intro (look for the copied text above to read the whole text): http://stackoverflow.com/questions/1028250/what-is-functional-reactive-programming

bryanjos

bryanjos

This looks pretty cool! @Qqwy and I have chatted a bit in the elixirscript channel on the Elixir slack.

The problems with using it with elixirscript are:

  • it doesn’t support dependencies yet
  • it doesn’t support processes elegantly at all yet. Also no OTP.

Looking at how GenFRP is used reminds me of a demo project I made with elixirscript and react.

I would love to be able to use something like GenFRP in elixirscript. Looks like it nicely wraps a proven pattern.

Qqwy

Qqwy OP

TypeCheck Core Team

I’ve had some time today to update GenFRP to a new version, which uses the init/0 function instead of the older initial_state/0 function (whose default implementation uses the initial_state: key that is part of the use GenFRP statement). It’s much clearer now, as it works the same as GenServer and friends.

The new version is 0.5.0; I expect that there are not a lot of changes that need to be done before releasing a stable 1.0 version (to be more exact, I think the current publicly exposed function names will remain stable).

As most of Elixir/Erlang is built using functional patterns, nearly all places can be handled by just wrapping something and then calling send_event directly.
But in the case something depends on some externally-stored state, the Callback module might be used instead. Right now GenFRP uses the Petick library to allow callbacks that fire every x milliseconds. This is built-in as I believe that this is a very common thing that people will want to do.
I am wondering however if there are more things that GenFRP could/should provide built-in callbacks for.
This is the single thing I’d like to be sure of before releasing a 1.0. Any suggestions are highly appreciated! :slight_smile:

(I hope this post is coherent; I just got back from the Global Game Jam and slept very little these last 50 hours…)

— All posts loaded —

Where Next? Top

Trending in Announcing Top

bluzky
You may know https://ui.shadcn.com/, a UI component library for React. I really love it’s design style and components. I’ve built some co...
387 15136 120
New
wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 11030 135
New
shahryarjb
The Chelekom project is a library of Phoenix and LiveView components generated via Mix tasks to fit developer needs seamlessly. One of i...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New

Other Trending Topics Top

mudasobwa
I am seeing a lot of aplications of Argumentum ad Vericundiam in software discussions. They do link some piece of writing and point us to...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New
Herve37
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using. We’re particularly inte...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
lawik
I was thinking since Goatmire Elixir turned out pretty good I should maybe do another one. 30th of Sep - 2nd of Oct this year./ The firs...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews