Vous cherchez un anamorphisme, ou un pliage inversé -
// unfold : ((r, state) -> List r, unit -> List r, state) -> List r
const unfold = (f, init) =>
f ( (x, next) => [ x, ...unfold (f, next) ]
, () => []
, init
)
// sampleData : List { id: Int }
const sampleData =
unfold
( (next, done, i) =>
i > 25
? done ()
: next ({ id: i }, i + 1)
, 0
)
console .log (sampleData)
// [ { id: 0 }, { id : 1 }, ... { id: 25 } ]
Vous pouvez avoir une intuition sur la façon dont unfold
fonctionne en le voyant utilisé dans d'autres programmes courants -
// unfold : ((r, state) -> List r, unit -> List r, state) -> List r
const unfold = (f, init) =>
f ( (x, next) => [ x, ...unfold (f, next) ]
, () => []
, init
)
// fibseq : Int -> List Int
const fibseq = init =>
unfold
( (next, done, [ n, a, b ]) =>
n === 0
? done ()
: next (a, [ n - 1, b, a + b ])
, [ init, 0, 1 ]
)
console .log (fibseq (10))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
La mise en œuvre de unfold
n'est qu'une possibilité. Bricolez et mettez-la en œuvre de la manière de votre choix -
// type Maybe a = Nothing | Just a
// Just : a -> Maybe a
const Just = x =>
({ match: ({ Just: f }) => f (x) })
// Nothing : unit -> Maybe a
const Nothing = () =>
({ match: ({ Nothing: f }) => f () })
// unfold : (state -> Maybe (a, state), state) -> List a
const unfold = (f, init) =>
f (init) .match
( { Nothing: () => []
, Just: ([ x, next ]) => [ x, ...unfold (f, next) ]
}
)
// fibseq : Int -> List Int
const fibseq = init =>
unfold
( ([ n, a, b ]) =>
n === 0
? Nothing ()
: Just ([ a, [ n - 1, b, a + b ] ]) // <-- yikes, read more below
, [ init, 0, 1 ]
)
console .log (fibseq (10))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
J'ai triché un peu plus haut en utilisant un []
comme un tuple. Cela a permis de raccourcir le programme, mais il est préférable de modéliser explicitement les choses et de prendre en compte leurs types. Vous avez marqué cette question avec Programmation fonctionnelle Cela vaut donc la peine de faire un effort supplémentaire pour supprimer ce type de traitement implicite de nos programmes. En montrant cela comme une étape séparée, nous isolons une technique qui peut être appliquée non seulement à unfold
mais pour tout programme que nous concevons -
// type Maybe a = Nothing | Just a
// type Tuple a b = { first: a, second: b }
// Just : a -> Maybe a
const Just = x =>
({ match: ({ Just: f }) => f (x) })
// Nothing : unit -> Maybe a
const Nothing = () =>
({ match: ({ Nothing: f }) => f () })
// Tuple : (a, b) -> Tuple a b
const Tuple = (first, second) =>
({ first, second })
// unfold : (state -> Maybe Tuple (a, state), state) -> List a
const unfold = (f, init) =>
f (init) .match
( { Nothing: () => []
, Just: (t) => [ t.first, ...unfold (f, t.second) ] // <-- Tuple
}
)
// fibseq : Int -> List Int
const fibseq = init =>
unfold
( ([ n, a, b ]) =>
n === 0
? Nothing ()
: Just (Tuple (a, [ n - 1, b, a + b ])) // <-- Tuple
, [ init, 0, 1 ]
)
console .log (fibseq (10))
// [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
0 votes
Étroitement liées, voire dupliquées : Comment générer une plage de nombres de 0 à n dans ES2015 ? , Existe-t-il un mécanisme permettant de boucler x fois dans ES6 sans variables mutables ? y manière fonctionnelle d'itérer sur une plage en ES6