/action-graphs

Model the world in composable graphs to rapidly create state machines, asynchronous workflows, conversational experiences, and whatever else you can dream up.

Primary LanguageF#MIT LicenseMIT

Contributors Forks Stargazers Issues MIT License


Logo

Action-Graphs

Current Version: 0.0.0

Model the world in composable graphs to rapidly create state machines, asynchronous workflows, and conversational experiences (or whatever else you can dream up!)
Explore the docs »

View Demo (in progress) · Report Bug · Request Feature

Table of Contents

  1. About The Project
  2. Getting Started
  3. F# Quickstart
  4. Roadmap
  5. Contributing
  6. License
  7. Contact

About The Project

We offer a library for defining and operating over mixed type, composable graphs. Most graph definitions treat graphs as a pure data model, sticking to scholastic definitions where the graphs contain the same kinds of values and the most complicated edges are simply weights.

Action-Graphs takes this starting point and adds the ability to define not only which nodes are related in the graph, but also the ability to describe each connection as an independant action that a graph "walker" executes.

Getting Started

To get a local copy up and running follow these simple steps.

Prerequisites

The library is built on .net core 3.1 and written in F#.

Installation

  1. Clone the repo
    git clone https://github.com/goldenwitch/action-graphs.git
  2. Build ActionGraph.sln:
    • Using Visual Studio
      1. Open ActionGraph.sln and build
    • Using .NET Core CLI
      1. Go to project folder
      2. Run dotnet build ActionGraph.sln

F-sharp Quickstart

Write hello world with graph oriented programming in three simple steps!

First...

Create a new F# console app. F# Getting Started Guide

Add a reference to the Action-Graphs library.

Secondly...

Define your graph in json.

{
  //Your top level graph definition
  "Nodes": [
    {
      "Id": "Start", //Each node has an addressable id that is unique to the graph that defines it (in this case the top level definition)
      "Edges": [
        {
          "Id": "text", //Each edge also has a uniquely addressable id that is unique to the node it is on
          "Action": "console.text", //This action references a passed in function that should run when this edge is walked. This one is from the prebuilt console actions and just emits the value of the node to console.
          "To": "[End]" //A "contextual node selector" describing a relationship between this node and a destination
        }
      ],
      "Value": "Hello"
    },
    {
      "Id": "End",
      "Edges": [
        {
          "Id": "text",
          "Action": "console.text",
          "To": "[Start]"
        }
      ],
      "Value": "World"
    }
  ]
}

Save this as helloWorld.json in your project, or remember what you saved it for the next step.

Finally...

The last step is to import the graph, and pump the console input into it via a "walker".

open System
open ActionGraph
open ActionGraph.Expressions
open System.IO

//Our core loop that runs every time we send a console message.
let consoleLoop (graph, walker:Walker) =
    walker.Walk(graph, "text") //Walk our graph, following the "text" edge each time
    ()

let rec result(graph, walker) =
    Console.ReadLine() |> ignore //Ignore what the user says for this sample
    consoleLoop(graph, walker) //Run our console loop
    result(graph, walker)

[<EntryPoint>]
let main argv =
    Console.WriteLine("Press enter or say anything to navigate between the nodes and read their value out.")
    let edgeFunctions = Map.ofSeq(Prebuilts.ConsoleEdges) //These prebuilt edges include ways to output to console.
    let graphDefinition = ActionGraph.Load(File.ReadAllText("helloWorld.json"), edgeFunctions) //Load our JSON as a graph, and enable the specific edge functions
    match graphDefinition with //Here we are handling the case in which we don't succeed at loading our graph
    | Some g ->
        let playerWalker = //Create a "walker" which points to a specific place in the graph and follows the edges between nodes.
            {
                CurrentNode = g.Nodes.[StringValue "Start"]
            }
        result(g, playerWalker) //Start the console loop, passing in the walker to go walk the graph
    | None -> ()

    0 // return an integer exit code

Console log screenshot

For more examples, please refer to the Documentation

Roadmap

See the open issues for a list of proposed features (and known issues).

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.

Contact

Please open github issues if you run into any grief.