Tracery is a text-generation language mostly used for twitter bots.
See Tracery.io for more information.
fromJson : String -> Result Json.Decode.Error Grammar
Turns a tracery json-string into a generator
import Json.Decode
import Random
import Result.Extra
generate : Int -> String -> String
generate seed json =
json
|> Tracery.fromJson
|> Result.Extra.unpack
Json.Decode.errorToString
(\grammar ->
Random.step (Tracery.run grammar) (Random.initialSeed seed)
|> Tuple.first
)
A tracery json is a object that has a origin
field.
The #
and \
characters need to be escaped.
"""
{ "origin": "The \\\\# and \\\\\\\\ characters need to be escaped."}
"""
|> generate 42
--> "The # and \\ characters need to be escaped."
If you provide a list, tracer will tick an element at random.
"""
{ "origin": ["I like cats","I like dogs"]}
"""
|> generate 42
--> "I like cats"
You can reference other fields using #..#
"""
{ "origin": ["I have two pets: a #pet# and a #pet#"]
, "pet": ["cat","dog","fish","parrot"]
}
"""
|> generate 42
--> "I have two pets: a dog and a cat"
You can also save partially evaluated strings
"""
{ "origin": ["I both have a #myPet# and a #myPet#."]
, "myPet" : "#petWithColor#"
, "petWithColor" : ["black #pet#", "white #pet#", "brown #pet#"]
, "pet": ["cat","dog","fish","parrot"]
}
"""
|> generate 41
--> "I both have a white cat and a white parrot."
Definitions may also be recursive.
"""
{ "origin": ["I have #pets#"]
, "pets": ["a #pet#","a #pet# and #pets#"]
, "pet": ["cat","dog","fish","parrot"]
}
"""
|> generate 20
--> "I have a fish and a cat and a dog"
You can define constants by providing a string instead of a list.
"""
{ "origin": ["My #favoritePet# is the best #favoritePet# in the world"]
, "favoritePet" : "#pet#"
, "pet": ["cat","dog","fish","parrot"]
}
"""
|> generate 42
--> "My dog is the best dog in the world"
You may define sub-definitions to organize your definitions.
"""
{ "origin": ["My #cat#","My #dog#"]
, "cat":
{ "origin":"cat is named #name#"
, "name": ["Cleopatra","Cesar"]
}
, "dog":
{ "origin":"dog is named #name#"
, "name": ["Athena","Zeus"]
}
}
"""
|> generate 42
--> "My cat is named Cleopatra"
run : Grammar -> Random.Generator String
Runs a grammar until it ends.
Some recursive definitions might take a long time.
Use runTo
if you want to avoid long waiting times.
runTo : List String -> Grammar -> Random.Generator Grammar
Runs a grammar until it reaches a key in the list.
import Json.Decode
import Random
import Result.Extra
generateTo : List String -> ({variable:String} -> String)-> Int -> String -> String
generateTo list fun seed json =
json
|> Tracery.fromJson
|> Result.Extra.unpack
Json.Decode.errorToString
(\grammar ->
Random.step (Tracery.runTo list grammar) (Random.initialSeed seed)
|> Tuple.first
|> toString fun
)
"""
{ "origin": ["A #color# #animal#"]
, "color": ["black","white","gray"]
, "animal":
[ "cat, looking at a #color# #animal#"
, "bird."
]
}
"""
|> generateTo ["animal"] (\{variable} -> "dog.") 42
--> "A black dog."
toString : ({ variable : String } -> String) -> Grammar -> String
Will just write the current output.
use run or runTo, to actually compute something.