Orasund / elm-tracery / Tracery.Grammar

Creates a string generator based on a syntax.

Grammar


type alias Grammar =
{ output : List Tracery.Command.Command
, stack : List Tracery.Command.Command
, next : Maybe Tracery.Command.Command
, constants : Dict String (List Tracery.Command.Command)
, definitions : Dict String Tracery.Syntax.Definition 
}

fromDefinitions : Dict String Tracery.Syntax.Definition -> Grammar

Turns Definitions into a Grammar.

toString : ({ variable : String } -> String) -> Grammar -> String

Prints the Grammar

Generating

generateWhile : (Grammar -> Basics.Bool) -> Strategy -> Grammar -> Random.Generator Grammar

Generates a string while a predicate is valid

import Dict
import Json.Decode
import Random exposing (Generator)
import Result.Extra
import Tracery.Syntax exposing (Definition(..), Expression(..))
import Set

andThenToString : ({ variable : String } -> String) -> Int -> (Grammar -> Generator Grammar) -> Grammar -> String
andThenToString fun seed gen grammar =
    Random.step (gen grammar) (Random.initialSeed seed)
        |> Tuple.first
        |> toString fun

input : Grammar
input =
    [ ( "origin", Choose [ [ Value "A ", Variable "animal" ] ] )
    , ( "animal"
      , Choose
            [ [ Value "cat, looking at a ", Variable "animal" ]
            , [ Value "bird." ]
            ]
      )
    ]
        |> Dict.fromList
        |> fromDefinitions

input
|> andThenToString (\{variable} -> "dog.") 42 (generateWhile (\_ -> True) defaultStrategy)
--> "A cat, looking at a cat, looking at a cat, looking at a cat, looking at a bird."

input
|> andThenToString (\{variable} -> "dog.") 42 (generateWhile (\_ -> True) (noRecursionStrategy (Set.fromList ["animal"])))
--> "A bird."

generateOutput : (Grammar -> Basics.Bool) -> Strategy -> Grammar -> Random.Generator Grammar

Generates an output found in the resulting grammar.

You can use generateCommands instead, If you intend to get the output right away.

generateNext : Strategy -> Grammar -> Random.Generator Grammar

Computes the command in grammar.next.

Afterwards the next command gets loaded

import Dict
import Json.Decode
import Random exposing (Generator)
import Result.Extra
import Tracery.Syntax exposing (Definition(..), Expression(..))

andThenToString : ({ variable : String } -> String) -> Int -> (Grammar -> Generator Grammar) -> Grammar -> String
andThenToString fun seed gen grammar =
    Random.step (gen grammar) (Random.initialSeed seed)
        |> Tuple.first
        |> toString fun

input : Grammar
input =
    [ ( "origin", Choose [ [ Value "A ", Variable "animal" ] ] )
    , ( "animal"
      , Choose
            [ [ Value "cat, looking at a ", Variable "animal" ]
            , [ Value "bird." ]
            ]
      )
    ]
        |> Dict.fromList
        |> fromDefinitions

using this function, you can step through the computation

input
|> andThenToString (\{variable} -> "<" ++ variable ++ ">.") 42 (generateNext defaultStrategy)
--> "A <animal>."

The second step does nothing (some steps only perform internal rearrangements)

input
|> andThenToString (\{variable} -> "<" ++ variable ++ ">.") 42
    (\g -> g
        |> (generateNext defaultStrategy)
        |> Random.andThen (generateNext defaultStrategy)
    )
--> "A <animal>."

But after a few more steps (and some rewinding), we get the result

input
|> andThenToString (\{variable} -> "dog.") 42
    (\g -> g
        |> (generateNext defaultStrategy)
        |> Random.andThen (generateNext defaultStrategy)
        |> Random.andThen (generateNext defaultStrategy)
        |> Random.map rewind
        |> Random.andThen (generateNext defaultStrategy)
         |> Random.andThen (generateNext defaultStrategy)
    )
--> "A cat, looking at a dog."

Strategy


type alias Strategy =
String -> List Tracery.Syntax.Expression -> Basics.Bool

The strategy specifies the algorithm to choose an option

defaultStrategy : String -> List Tracery.Syntax.Expression -> Basics.Bool

This strategy will choose any option

noRecursionStrategy : Set String -> String -> List Tracery.Syntax.Expression -> Basics.Bool

This strategy will never choose a recursive option

onlyRecursionStrategy : Set String -> String -> List Tracery.Syntax.Expression -> Basics.Bool

This strategy will only chose recursive options

Technical Utilities

toNext : Grammar -> Grammar

Moves to the next command without executing anything.

toNext : Grammar -> Grammar
toNext grammar =
    grammar |> withCommands grammar.stack

withCommands : List Tracery.Command.Command -> Grammar -> Grammar

Sets Commands of a Grammar.

skip : Grammar -> Grammar

Puts the current command on the output (without executing it) and then gets the next command.

rewind : Grammar -> Grammar

sets the output as input.

end : Grammar -> Grammar

set the remaining commands as output