Skip to content

Instantly share code, notes, and snippets.

@mastoj
Created October 17, 2017 11:25
Show Gist options
  • Save mastoj/6ee096316f0a6cde6413bc1b42a5b160 to your computer and use it in GitHub Desktop.
Save mastoj/6ee096316f0a6cde6413bc1b42a5b160 to your computer and use it in GitHub Desktop.
Example of lightweight railway oriented programming in go (but some typing is lost)
package main
import (
"fmt"
)
type Result struct {
Error error
Data interface{}
}
type Action struct {
DoThis int
}
type Command func(data interface{}) Result
var command1 Command = func(data interface{}) Result {
i := data.(Action)
if i.DoThis == 0 {
return Result{
Error: (fmt.Errorf("Do1 error")),
Data: nil,
}
} else if i.DoThis == 1 {
return Result{
Error: nil,
Data: "",
}
}
return Result{
Error: nil,
Data: fmt.Sprintf("yolo: %v", i),
}
}
func Do2(data interface{}) Result {
i := data.(string)
if i == "" {
return Result{
Error: (fmt.Errorf("Do2 error")),
Data: nil,
}
}
return Result{
Error: nil,
Data: "It works: " + i,
}
}
func Do3(data interface{}) Result {
return Result{
Error: nil,
Data: fmt.Sprintf("Do3: %v", data),
}
}
func Compose2(command1, command2 Command) Command {
return func(input interface{}) Result {
res1 := command1(input)
if res1.Error != nil {
return res1
}
return command2(res1.Data)
}
}
func (command1 Command) Compose(command2 Command) Command {
return Compose2(command1, command2)
}
func ComposeAll(commands []Command) Command {
if len(commands) == 0 {
return func(data interface{}) Result {
return Result{}
}
}
command := commands[0]
for i := 1; i < len(commands); i++ {
command = command.Compose(commands[i])
}
return command
}
func lift(c func(data interface{}) Result) Command {
return c
}
func main() {
c3 := lift(Do3)
commands := []Command{
command1,
lift(Do2),
c3,
c3,
c3,
c3,
c3,
c3,
c3}
composedCommand1 := ComposeAll(commands)
composedCommand2 :=
command1.Compose(lift(Do2)).Compose(c3).Compose(c3).Compose(c3).Compose(c3).Compose(c3).Compose(c3).Compose(c3)
execute := func(command Command, data Action) {
res := command(data)
if res.Error != nil {
fmt.Println("Error man: ", res.Error)
} else {
fmt.Println("Success: ", res.Data)
}
}
execute(composedCommand1, Action{DoThis: 0})
execute(composedCommand1, Action{DoThis: 1})
execute(composedCommand1, Action{DoThis: 2})
execute(composedCommand2, Action{DoThis: 0})
execute(composedCommand2, Action{DoThis: 1})
execute(composedCommand2, Action{DoThis: 2})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment