svarlet

svarlet

Hi all,

Let’s assume we are all coding a poker game as a purely functional library (=> no processes at this stage). If you don’t feel comfortable with poker, any other familiar multiplayer game will do.

How would you model it?
How would you design user interactions?
How would you validate user actions?

Thanks

First Post!

peerreynders

peerreynders

So at some point will there be processes? In that case, have you already had a look at The Erlangelist: To spawn, or not to spawn?. It looks at bridge for the purposes of the article - though as it uses processes it may not address your exact concerns (I also don’t recall any validations).

Most Liked

OvermindDL1

OvermindDL1

As a state blob that I pass around. I do exactly this in the languages I’ve implemented in Elixir, just passing around an env struct, threading it through every function.

Well in purely functional you cannot get user input other than before your code runs, so I’d do it via the repl with them calling the function with the current state along with their action as a kind of ‘event input’.

In reality you need some way to get user actions at runtime, a Haskell IO monad can do that functionally (by blackboxing using input and pretending it has been there since the start even if it has not) or via event passing between purely functional processes or so.

Depends entirely on what you want to validate, but you’d do it in that above process function.

This is not actually that hard. Given a language with Sum types (or tagged tuples on the BEAM) I’d just have each action be part of that sum type that they pass in with the state, and via simple pattern matching you only handle what is valid for a given state/event mix. With matchers it is trivial to just work on the valid actions and crash on the invalid (with perhaps a single wrapper to give pretty errors).

Likewise, I just implemented an FSM on gen_server anytime I needed a FSM, just by pattern matching states and such.

OvermindDL1

OvermindDL1

Crash back to the wrapper, which then returns the original untouched state and the error.

svarlet

svarlet OP

Thanks for recommending Exceptional. I already had a look at it not so long ago but without context I didn’t give it enough importance.

That helped me quite a bit this time and put on a better track too. Essentially, I refactored a bit my code from something like this:

def user_action(state, param) do
  cond do
    validate_param() ->
      {:error, :reason1}
    validate_state() ->
      {:error, :reason2}
    ...
    true ->
      # the actual logic
end

to

def user_action(state, param) do
  param
  |> validate_param()
  ~> validate_state()
  ~> do_user_action()
end

where validate_xxx function return either the param unchanged or an exception (return, not raise). You could say that it’s not much but the code is much more readable that way. Validators are defined as simple functions and I can now define them outside my module if I need to.

Last Post!

cdegroot

cdegroot

I’ve had decent success with a module per state and module-defined state, managed by (in this case) a GenServer that basically just forwards calls to state.current_state_module.do_something(state.module_state). For example, my Raft library has a module for “Leader”, “Follower” and “Candidate” and functions transition_from in each one to handle state transitions (with pattern matching on the old state - there is no transition_from(:follower, ...) in the Leader module so that’s automatically an invalid state transition.

It’s simple to test (I usually want to write code in a mix of top-down and bottom-up, mostly guided by tests).

(also, I need to write log compaction for that library so I can call it mostly done ;-))

Where Next? Top

Trending in Questions Top

water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New

Other Trending Topics Top

budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews