• Stars
    star
    109
  • Rank 319,077 (Top 7 %)
  • Language
    Haskell
  • License
    BSD 3-Clause "New...
  • Created over 7 years ago
  • Updated almost 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An extensible event-driven application framework in haskell

Eve

Join the chat at https://gitter.im/eve-framework/Lobby Hackage

An extensible event-driven application framework in haskell for building embarassingly modular software.

Documentation

You can find hackage documentation for eve HERE

Getting started

Building A Game in Eve

Here's a guide which walks you through building your first application in Eve from start to finish, it's quite thorough and it's a great place to start!

If you have any issues (and I'm sure there'll be a few; it's a new project!) please report them here.

Core Principles

Eve's core principle is making it easy to build programs in a modular way. There are two key concepts in Eve which you should be aware of:

  • Events
  • State

Events

Eve provides many useful combinators for dispatching events and adding listeners to events, events are a broad concept in Eve and can be triggered by user-interaction, file-changes, even network sockets! Anything you can think of really! Each time an event is fired, your app 'reacts' by running any associated listeners on the given event.

The functions you need to know are (with simplified types, see the real type in the hackage docs):

  • dispatchEvent :: forall eventType result m. (Monad m, Monoid result) => eventType -> m result
  • addListener :: forall eventType result m. (Monad m, Monoid result) (eventType -> m result) -> m ListenerId

As I mention above, these types are simplified a bit (and yet they still look complicated!). Actually, the types look so complex so that they're simpler to use! The forall makes it so that you can call dispatchEvent with ANY Typeable type and it will run the proper event listeners which were registered by addListener; those listeners can alter app state, or even dispatch more events! If the listeners return some (monoidal) value then the results from all listeners are combined with mappend and are returned. That's pretty much it!

Here's a quick example for those who need to see some code:

import Eve
import Data.Monoid

-- Define an event to listen for, in this case we don't even need any data alongside it.
data ComputeScore = ComputeScore

-- Define some computations which calculate some aspect of score.
-- We accept an argument of 'ComputeScore' to define what this is a listener for
scoreContributor1, scoreContributor2 :: ComputeScore -> App (Sum Int)
scoreContributor1 _ = do
  ... -- do some calculation over app state to determine one aspect of score
  return (Sum score)

scoreContributor2 _ = do
  ... -- Calculate some other aspect of the score
  return (Sum score)

-- In eve's initialization block we register the listeners, we could add these listeners anywhere
main :: IO ()
main = eve_ $ do
  ... -- other initialization (e.g. key listeners, etc.)
  addListener_ scoreContributor1
  addListener_ scoreContributor2

  -- This dispatches the triggering event and monoidally sums all the individual score components!
computeTotalScore :: App (Sum Int)
computeTotalScore = do
  Sum score <- dispatchEvent ComputeScore
  return score

State

Next we see how Eve handles state. Eve seeks to be as extensible as possible so it makes very few assumptions about the type of state that you (or your extensions) plan to store. You can define a type of state yourself using data and then provide actions which alter that state using a MonadState instance (from mtl). Don't worry if you don't know what that means, here's a real quick example which uses the combinators from the lens library to make a few simple state changes.

import Eve
import Control.Lens
data MyState = MyState
  { _myInt :: Int
  , _myString :: String
  }
makeLenses ''MyState

-- This alters some state and returns the old string for some reason.
doSomething :: Action MyState String
doSomething = do
  oldString <- use myString
  myString .= "Hi!"
  myInt += 1
  return oldString

So what does this gain us? Well now if we have a MyState somewhere in our app we can run that Action on it! We can also register that Action as a listener for some event!

Now for the interesting part; handling state for extensions. This is usually a bit tricky since the types that an extension might use aren't known by you (the app author). Eve takes care of this by providing an interface for extensions to store and keep track of arbitrary types, while still allowing other extensions to run actions that it exports. This is where the HasStates typeclass comes in; here's the honest to goodness implementation:

class HasStates s  where
  states :: Lens' s States

If your state implements that typeclass, then extensions can store their own states inside it! It's pretty easy to implement too, let's add it to our MyState.

import Eve
import Control.Lens
data MyState = MyState
  { _myInt :: Int
  , _myString :: String
  , _myStates :: States
  }
makeLenses ''MyState

instance HasStates MyState where
    states = myStates

Done! We added a new field which has the type States which is exported by Eve. Then we just took the lens created by makeLenses and used it in our instance. That's it! Now extensions can store their own state inside Action MyState by using the stateLens; check out the hackage docs on that for more info on how to do it!

Those are the basics, but you can do much more than that if you like! Eve also lets you add listeners and dispatch events on an Object specific basis! If you have a copy of some state (let's say a single instance of an Enemy in a game) you can dispatch events over that enemy individually and any registered (Action Enemy) callbacks will be run without affecting any other enemies! Check out HasEvents to see how that works.

One last cool feature is that event listeners can return information! If your event listener results in a return value that's a Monoid (like a list, or string for example) you can collect the responses of all the listeners when you call dispatchEvent. This is a great way for your application to 'ask' extensions about their state.

When designing applications in Eve; it's crucial to think about how the state of you application will be stored, and how different components interact. Eve works best when components are separated and communicate with each-other through events. This is because it allows those who will eventually write extensions to your application to 'hook' into those events to add functionality.

There are some definite Pros and Cons to Eve's approach:

Pros

  • Implementing most core functionality using the event system your app remains extensible.
  • Flexibility & Adaptability; applications can be written in such a way that users can replace entire components with alternate versions.

Cons

  • Module cross-dependencies makes the community infrastructure more fragile,
  • This architecture takes some getting used-to.

Contributing

Installation

Eve uses Stack for reproducible builds.

  1. Install stack
  2. Clone this repo and cd into the directory
  3. Run stack build

Running Tests

  • stack test

Contributions

Chatting about features is a key part of Eve's development; come join us in the Chat Room to discuss features or improvements!

Related Works

More Repositories

1

rasa

Extremely modular text editor built in Haskell
Haskell
612
star
2

slick

Static site generator built on Shake configured in Haskell
Haskell
204
star
3

void-space

Well-Typed Typing Tutor where you Type Types... in space... yup, you heard me
Haskell
140
star
4

wc

Beating unix `wc` in Haskell
Haskell
136
star
5

lens-regex-pcre

Text lenses using PCRE regexes
Haskell
126
star
6

SitePipe

Yet another static site generator - non-opinionated, value-level. Less magic == easier to understand
Haskell
119
star
7

comonads-by-example

Comonads By Example Conference talk
Haskell
89
star
8

Firefly

Simple Haskell http framework
Haskell
87
star
9

json-to-haskell

In goes JSON, out comes a complete Haskell model complete with instances! CLI and web interface available.
Haskell
83
star
10

astar-monad

A smart A* search monad transformer which supports backtracking user-state!
Haskell
81
star
11

jet

A structural editor for JSON values
Haskell
78
star
12

Advent-Of-Code-Polyglot

Examples of "Advent Of Code" solutions in many programming languages.
Python
72
star
13

mad-props

Forward-propagating Constraint Solver monad. Good for solving Sudoku, N-Queens, etc.
Haskell
66
star
14

lens-csv

Lensy interface for parsing CSV's
Haskell
42
star
15

LumberJack

A terminal-ui log watcher written in Go using the Flux architecture
Go
38
star
16

conway

Conway's game of life in 100 lines or less!
Haskell
34
star
17

tempered

Templating engine based on shell interpolation
Haskell
31
star
18

unipatterns

Helpers which allow safe partial pattern matching in lambdas
Haskell
31
star
19

session-sauce

Shell plugin for managing tmux sessions
Shell
29
star
20

slick-template

A template for quickly building sites with slick
CSS
27
star
21

grids

Arbitrary dimension type-safe grids
Haskell
26
star
22

copy-pasta

Shell
26
star
23

dumbwaiter

Extensible HTTP Web server configured entirely by a yaml file
Haskell
25
star
24

haskell-stack-travis-ci

Dead simple setup tools for running a Haskell build matrix using stack for several versions.
Shell
23
star
25

lens-filesystem

Lens interface for your filesystem
Haskell
22
star
26

selections

Haskell Package for operating with selections over an underlying functor
Haskell
22
star
27

btt-quicknav

HTML overlay for quickly navigating your computer
JavaScript
19
star
28

lens-errors

Handling errors which occur deep inside lens-chains
Haskell
17
star
29

proton

Haskell Profunctor Optics experiments
Haskell
15
star
30

Type-Tac-Toe

Type-safe tic-tac-toe using Typesafe programming in Haskell
Haskell
15
star
31

wave-function-collapse

Wave function collapse procedural generation for arbitrary graphs
Haskell
15
star
32

catalyst

There are many category theory implementations, but this one is mine
Haskell
14
star
33

update-monad

An implementation of the Update Monad and a 'Free' version from https://danelahman.github.io/papers/types13postproc.pdf
Haskell
13
star
34

Candor

A toy Parser+Compiler+Typechecker
Haskell
12
star
35

recursive-zipper

Zippers for cofree types
Haskell
12
star
36

climbing-fp-ladder

A record of examples and anecdotes as I ascend the ladder of Functional Programming
12
star
37

charter

Haskell charting library
Haskell
10
star
38

trek

Haskell
10
star
39

vimprove

A series of daily tasks/info to learn vim from beginner to expert one day at a time.
Shell
9
star
40

react-tui

Haskell
9
star
41

dont-argue

Dead-simple command line arguments for python scripts.
Python
8
star
42

advent-of-code-haskell

Advent of Code Solutions in Haskell
Haskell
7
star
43

BoxKite

A very simple blog framework that emphasizes managing posts in a plain-text directory structure. Runs on Google App Engine, but can also be exported as a static site.
Python
7
star
44

flux-monoid

A monoid which counts changing values in a sequence
Haskell
6
star
45

ffs

A Fuse-compatible Functional File System with @isovector
Haskell
6
star
46

lens-friends

Just some lens combinator experiments :)
Haskell
5
star
47

jaunt

a jq clone in purescript
PureScript
5
star
48

json-to-haskell-web

Haskell
5
star
49

brick-filetree

A brick widget for exploring your filetree
Haskell
5
star
50

vim-committed

Sends Desktop notifications to remind you to commit.
Vim Script
4
star
51

CMPT481

Human Computer Interaction Project
JavaScript
4
star
52

rxjs-tutorial

Walkthrough of building a simple webapp using different rxjs patterns
TypeScript
4
star
53

jsonf

An educational JSON functor library for teaching recursion-schemes
Haskell
4
star
54

haskell-library-template

Template for Haskell libraries
Haskell
4
star
55

rust-advent-of-code

Rust
4
star
56

recursion-schemes-by-example

JavaScript
4
star
57

monad-suspend

Experimental Cost-Annotated Self-Yielding Coroutines
Haskell
4
star
58

game-genre-per-day

Weird and whimsical video game genres everyday!
TypeScript
4
star
59

reactive-streams

Reactive stream combinators in Haskell! Implementations of Rx primitives based on the 'machines' library
Haskell
4
star
60

professor

An experimental http server written entirely with profunctors
Haskell
4
star
61

Wirehack

A small circuit-building game built in Haskell
Haskell
3
star
62

ChrisPenner.github.io

Basic Website
HTML
3
star
63

json-to-haskell-purescript

Generate Haskell datatypes from json objects
Dhall
3
star
64

free-cached

Cache previous runs of free monads
Haskell
3
star
65

substrate

File substitution tools I need for my book
Haskell
3
star
66

cards-against-corona

Elm
3
star
67

chip8

Rust
3
star
68

type-arithmetic

Proofs of types as a semiring via Curry-Howard Isomorphism
Haskell
3
star
69

purescript-node-readline-aff

A wrapper around Node.ReadLine for use with the Aff Monad.
PureScript
3
star
70

Flow

An experimental Haskell FRP (streams) library
Haskell
3
star
71

j-lang-haskell

JLang combinators in Haskell
Haskell
3
star
72

purescript-flow

A redux-style application framework
PureScript
3
star
73

catalyst-build

Experimental build system based on composition of categories & arrows
Haskell
3
star
74

focus

cli utility for hacking and slashing data
Haskell
3
star
75

rx-prop

Propagator based reactive extensions library
Haskell
2
star
76

rsi

Structural regex based command pipelines
Haskell
2
star
77

propellant

Foray into propagator networks in Haskell
Haskell
2
star
78

concurrency-comparison

Comparison of basic concurrency primitives and tasks in Haskell and Golang
Haskell
2
star
79

mustache-shake

Build rules for compiling mustache templates using shake
Haskell
2
star
80

scavenger

A basic texting scavenger hunt using Twilio
Python
2
star
81

mailing-list-reader

Haskell
2
star
82

Kaleidoscope

Working through the Kaleidoscope llvm compiler project
Haskell
2
star
83

delve

Terminal UI File Browser
Haskell
2
star
84

free-contravariant

An exploration into free contravariant functors
Haskell
2
star
85

schemer

Uber basic scheme interpreter
Haskell
2
star
86

continuity

Composable Component Framework
Haskell
2
star
87

eve-cli

Terminal event handlers and rendering for `eve` programs
Haskell
2
star
88

sheets

Overly complex attempt at typesafe spreadsheets
Haskell
2
star
89

Simpleton-Algebraics

Learn about Functional Algebraic Types without making your head explode.
2
star
90

flags

Compiles a declarative bash script configuration into a 100% bash flags and argument parser.
Shell
2
star
91

dual-free

Library for combined free & cofree trees into a single type.
Haskell
2
star
92

cofree-zippers

Just an experiment, move along :)
Haskell
1
star
93

grids-images

Tools for interacting with images using grids
Haskell
1
star
94

overlord

Logs dashboard for all your local servers.
JavaScript
1
star
95

SPA-GAE-template

Single page application template for google app engine using react-redux
JavaScript
1
star
96

SpareSpeare

Shakespeare Filler Text Generator
Python
1
star
97

cmpt317

Python
1
star
98

test-specialization

Companion to a blog post on testing patterns in Haskell
Haskell
1
star
99

reified-dicts

Experiment to reify symbols/nats into constraints by matching them within a known set.
Haskell
1
star
100

unison-testing

Just a scrap unison codebase for testing
1
star