Giter Site home page Giter Site logo

doctor-smith / evoleq Goto Github PK

View Code? Open in Web Editor NEW
1.0 2.0 0.0 466 KB

Functional programming in terms of dynamical systems. A declarative approach to application design.

License: Other

Kotlin 100.00%
kotlin coroutine functional declarative dynamical-systems process-dsl process dsl structured-concurrency

evoleq's Introduction

Download License

Evoleq

Functional programming in terms of dynamical systems. A declarative approach to application design.

Goals

  • Write applications (and their functional flows) using a process-dsl.
  • Unify synchronous and asynchronous coding
  • Arrange asynchronous, concurrent components of applications in an unbreakable process hierarchy.
  • Design applications in a really composable way.

Build your Project with Evoleq

Evoleq is hosted on bintray/jcenter

Gradle

compile( "org.drx:evoleq:1.1.1" )

Maven

<dependency>
    <groupId>org.drx</groupId>
    <artifactId>evoleq</artifactId>
    <version>1.1.0</version>
</dependency>

Notes

  • Evoleq targets JVM 1.8

The Core

The functional heart of the library consists of just one powerful function (and a variation for suspended flows).

The Main Function

/**
 * Evolution
 */
tailrec suspend fun <D, T> evolve(
    initialData: D,
    conditions: EvolutionConditions<D, T>,
    flow: (D) -> Evolving<D>
) : Evolving<D> = when( conditions.ok() ) {
    false -> etaEvolving( initialData )
    true -> {
        val evolvedData: D = flow ( initialData ).get()
        evolve(
            evolvedData,
            conditions.update( evolvedData )
        ){
            data -> flow ( data )
        }
    }
}

The main data type

The main idea behind the following data type is to provide a uniform way to treat synchronous and asynchronous processes.

package org.drx.evoleq.evolving

interface Evolving<out D> {

    val job: Job

    suspend fun get() : D
}

It is obvious that implementations of the Evolving type are monadic when they are functorial. The implementations provided in this library are all functorial.

Terminology

Evoleq is inspired by the theory of dynamical systems. Roughly speaking, a (discrete) dynamical system can be described as follows: if you have an invertible map T: X->X, where X is a set, then T induces a map Φ : Z x X -> X: (n,x)->Tn(x) on X (here, Z is the set of integers) with the following properties:

  • Φ(0,x) = x, for all elements x of X,
  • Φ(n+m,x) = Φ(n, Φ(m,x)) for all integers n,m and all x in X.

Φ is called the flow of T on X or simply a dynamical system. Further, mathematicians would say that X evolves under the flow of T.

The requirement on T in being invertible is too strong for our purposes. We will keep the terminology but allow all transformations T: X->X. Doing so, we end up with a somehow monoidal version of flows Φ: N x X -> X: (n, x)->Tn(x), where N is the set of non-negative integers.

Flows, Stubs and Gaps

Use stubs, gaps and flows to organize the evolution maps:

Example: First one wins the race

val stub = racingStub<Int,Int> {
    timeout (1_000 )
    // drivers
    driver{ Parallel{
        delay(150)
        1
    }}
    driver{ Parallel{
        delay(100)
        2
    }}
    driver{ Parallel{
        delay(10)
        3
    }}
    // gap
    gap{
        from{ OnDemand{ null } }
        to{x , y-> OnDemand{
            when(y==null){
                true -> x
                false -> y
            }
        }}
    }
}
val flow = stub.toFlow( conditions( once() ))
val result = flow.evolve(0).get() // 2

Example (schematic): Intercept application shutdown with a confirmation dialog

/**
 * Application stub 
 */
val appStub = stub<Message> {
    evolve{ message -> when( message ) {
        is Message.Start -> TODO()
       
        // interception
        is Message.Close -> message.intercept(
            closeDialogStub,
            gap{
                from { message -> Parallel{ Dialog.Show } }
                to { message, dialog -> when(dialog) {
                    is Dialog.Ok -> OnDemand{ Message.CloseResponse }
                    is Dialog.Cancel -> OnDemand{ Message.Resume }
                    else -> OnDemand{ Message.Resume }
                } }
            }     
       )
             
       is Message.Resume -> TODO()
       is Message.CloseResponse -> OnDemand{ message }
    } }
}    
/**
 * Application flow
 */
val appFlow = appStub.toFlow<Message, Boolean>(
    conditions{
        testObject(true)
        check{ b -> b }
        updateCondition{ message -> message !is Message.CloseReponse }
    }
)

For convenience, we also give the definitions of the used data types

/**
 * Dialog message
 */
sealed class Dialog {
    object Show : Dialog()
    object Ok : Dialog()
    object Cancel : Dialog()
}
/**
 * Dialog stub
 */
val closeDialogStub: Stub<Dialog> = TODO()


/**
 * Application Messages
 */
sealed class Message {
    object Start : Message()
    object Close : Message()
    object CloseResponse : Message()
    object Resume : Message()
}

Example (schematic): Error handling

val stub = stub<D>{
    evolve{ data -> throw(Exception("Error Message")) }
}


val stub2 = stub.runCatchingErrors()
val d: D = TODO()
val result = stub2.evolve(ErrorCatcher(d)).get().error // thrown exception

Example (schematic): Handle incoming messages

val port: Actor<Message> = actor<Message>()

class Data<D>(val d: D, val message: Message = EmptyMessage)

val receiver = receivingStub<Data,Message>{
    receiver(port)
    gap{
        from { data: Data -> OnDemand{ data.message } } 
        to { data, message -> OnDemand{ data.copy( message= message) }}
    }
}


val flow = receiver.toFlow<Data, Boolean>(
    conditions{
        testObject( true )
        check { b->b }
        updateCondition{ data -> data.message <= 1000 }
    }
)

val run = flow.evolve( d )

GlobalScope.launch{
    Parallel<Unit>{
        (1..1000).forEach{ actor.send(Message(it)) }
    }
}

val result = run.get() // Data(d, 1000)

Examples

Take a look at the sources of evoleq-examples

Versions

Take a look at the version history.

evoleq's People

Contributors

doctor-smith avatar

Stargazers

 avatar

Watchers

 avatar  avatar

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.