Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

v0 source pure

Package markov is a deterministic Markov-chain text generator — a port of Go's canonical example "Generating arbitrar...

Readme View source

gno.land/p/moul/x/daily/markov/v0

Deterministic Markov-chain text generator — a port of Go's canonical example "Generating arbitrary text: a Markov chain algorithm" with math/rand replaced by a caller-supplied seed.

A Chain maps every two-word prefix to the list of words observed to follow it (duplicates kept, so frequency biases the walk), storing that map in a persistent avl.Tree. Build folds text into the chain; Generate walks it from the start prefix, picking one suffix per step from a small LCG seeded by the uint64 you pass — so generation is pure and replayable, and the caller decides where entropy comes from (on-chain, the block height). No chain imports, no ambient state.

1import "gno.land/p/moul/x/daily/markov/v0"
2
3c := markov.New()
4c.Build("it was the best of times it was the worst of times") // fold in a corpus
5words := c.Generate(40, seed)                                  // walk it, seeded
6c.Stats()                                                      // (totalWords, prefixCount)
7c.Iterate(func(prefix string, suffixes []string) bool { ... }) // inspect the map

Live demo: r/moul/x/daily/markovdemo · render it at /r/moul/x/daily/markovdemo/v0.


Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.

Dependency graph:

gno.land/p/moul/x/daily/markov/v0 dependency graph

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.

Overview

Package markov is a deterministic Markov-chain text generator — a port of Go's canonical example "Generating arbitrary text: a Markov chain algorithm" (https://go.dev/doc/codewalk/markov/) with math/rand replaced by a caller-supplied seed.

It is a pure library: it imports no chain APIs and reads no ambient state. A Chain maps every PrefixLen-word prefix to the list of words observed to follow it (duplicates kept, so frequency biases the walk), storing that map in a persistent avl.Tree. Build folds text into the chain; Generate walks it from the start prefix, picking one suffix per step from a small LCG seeded by the uint64 the caller passes — so generation is deterministic and replayable, and the caller decides where entropy comes from (on-chain, the block height).

A realm wires it up by holding a *Chain in a package-level var, calling Build to grow the corpus and Generate with a height-derived seed. For a complete, live example see the demo realm r/moul/x/daily/markovdemo(/r/moul/x/daily/markovdemo/v0).

Constants 1

const PrefixLen

1const PrefixLen = 2
source

PrefixLen is the number of words in a prefix. Two is the classic choice from the Go codewalk: long enough to sound plausible, short enough to keep the chain well-connected.

Functions 1

func New

1func New() *Chain
source

New returns an empty Chain ready to Build into.

Types 2

type Chain

struct
1type Chain struct {
2	table  avl.Tree
3	prefix Prefix
4	words  int
5}
source

Chain is a Markov chain over a persistent avl.Tree. table maps prefix key -> *suffixList; prefix is the rolling build window so successive Build calls extend one continuous corpus rather than restarting; words is the running word count.

Methods on Chain

func Build

method on Chain
1func (c *Chain) Build(text string) int
source

Build tokenizes text on whitespace and folds each word into the chain, recording it as a suffix of the current prefix and then shifting. It returns the number of words added. This is the analogue of Chain.Build from the codewalk.

func Generate

method on Chain
1func (c *Chain) Generate(n int, seed uint64) []string
source

Generate walks the chain from the start prefix, picking one suffix per step via an LCG seeded by seed, and returns up to n words. It stops early if it reaches a prefix with no recorded suffixes (a dead end). Pure: the same (n, seed) always yields the same words for a given chain.

func Iterate

method on Chain
1func (c *Chain) Iterate(fn func(prefix string, suffixes []string) bool) bool
source

Iterate calls fn for each prefix in ascending key order, passing the prefix key and the list of words recorded to follow it. Returning true from fn stops the iteration early; Iterate reports whether it was stopped that way.

func Stats

method on Chain
1func (c *Chain) Stats() (int, int)
source

Stats returns (totalWords, prefixCount) for the current chain.

type Prefix

slice
1type Prefix []string
source

Prefix is a sliding window of the last PrefixLen words seen. It mirrors the Prefix type in the original program.

Imports 2

Source Files 3