Skip to Content
Mélodium 0.10.3 is now available!
DocsExemples02. Flux & généricité

Flux & généricité

Source: tutorial/02_flow_and_generics See in Playground

Génère les entiers 1..upper, les répartit de part et d’autre de threshold, décale chaque moitié d’un offset différent, puis fusionne les deux moitiés en un seul flux : le tout avec deux petits traitements génériques définis dans le même fichier et réutilisés deux fois chacun.

Exécution

cd tutorial/02_flow_and_generics melodium run Compo.toml --upper 10 --threshold 5 --offset_above 100 --offset_below=-100
Note

Une valeur négative nécessite la forme --flag=valeur : --offset_below -100 échoue à l’analyse, car la ligne de commande interprète -100 comme un groupe d’options courtes plutôt que comme une valeur.

En exécutant avec --upper 10 --threshold 5, le flux at-or-below-threshold journalise 1, 2, 3, 4, 5 et above-threshold journalise 6, 7, 8, 9, 10 : le découpage symétrique qu’implique 1..10 autour de 5.

Optionnel : ajoutez --api-report et un jeton d’API (MELODIUM_API_TOKEN) pour voir la trace complète de cette exécution sur Cadence.CI.

Fonctionnement

Cet exemple non plus n’utilise aucun modèle : tout est traitement sans état, fonction, et deux traitements génériques maison.

Flux de données

Construction de la séquence

1..upper est construit avec generate, qui produit upper valeurs de remplissage, et count, qui les numérote à partir de 1 :

howMany: emit<u128>(value=upper) seed: generate<u128>(data=0) numbering: count<u128>() asI64: saturatingToI64<u128>() startup.trigger -> howMany.trigger,emit -> seed.length,stream -> numbering.stream numbering.count -> asI64.value,into -> split.value

Un traitement générique pour la répartition : aboveThreshold<N: PartialOrder>

aboveThreshold n’est instancié qu’une seule fois (sous le nom split) mais il est écrit de façon générique : il ne mentionne jamais i64 dans son corps, et fonctionne pour tout type ordonnable (PartialOrder). À l’intérieur, il construit un flux de même longueur rempli de la valeur threshold grâce à toVoid et fill, afin de pouvoir comparer élément par élément avec greaterThan, puis utilise ce flux de booléens pour répartir l’entrée en above/below avec filter :

treatment aboveThreshold<N: PartialOrder>(const threshold: N) input value: Stream<N> output above: Stream<N> output below: Stream<N> { asVoid: toVoid<N>() thresholdSt: fill<N>(value=threshold) isAbove: greaterThan<N>() partition: filter<N>() Self.value -> asVoid.value asVoid.iter -> thresholdSt.pattern Self.value -> isAbove.a thresholdSt.filled -> isAbove.b Self.value -> partition.value isAbove.is -> partition.select partition.accepted -> Self.above partition.rejected -> Self.below }

Self.value est lu trois fois ici (vers asVoid, isAbove, et partition) : lire plusieurs fois la même entrée est autorisé, seule l’écriture répétée sur une même entrée ne l’est pas.

Un second traitement générique : shift<N: Add>

shift est instancié deux fois (bumpAbove, bumpBelow) avec deux valeurs offset différentes : même traitement, même astuce toVoid + fill, qui alimente cette fois add :

treatment shift<N: Add>(const offset: N) input value: Stream<N> output shifted: Stream<N> { asVoid: toVoid<N>() offsetSt: fill<N>(value=offset) adder: add<N>() Self.value -> asVoid.value asVoid.iter -> offsetSt.pattern Self.value -> adder.a offsetSt.filled -> adder.b adder.sum -> Self.shifted }
bumpAbove: shift<i64>(offset=offset_above) bumpBelow: shift<i64>(offset=offset_below) split.above -> bumpAbove.value split.below -> bumpBelow.value

Fusion en un seul flux

merge entrelace les deux flux décalés sans ordre prévisible : en relançant le programme, l’ordre des journaux peut différer, ce qui est normal. Les flux Mélodium n’offrent aucune garantie d’ordre implicite entre branches :

combined: merge<i64>() bumpAbove.shifted -> combined.a bumpBelow.shifted -> combined.b

Un dernier count numérote le flux fusionné, simplement pour montrer que c’est un flux comme un autre.

Dépendances

[dependencies] std = "0.10.3" # flux de base, journalisation, structures de données