diff --git a/src/Fuzz.elm b/src/Fuzz.elm index 02695c7..116f56c 100644 --- a/src/Fuzz.elm +++ b/src/Fuzz.elm @@ -36,6 +36,7 @@ Instead of using a tuple, consider using `fuzzN`. import Array exposing (Array) import Char +import Fuzz.AndThen import Fuzz.Internal as Internal exposing (Fuzz(..), invalidReason) import Lazy.List exposing (LazyList) import Random.Pcg as Random exposing (Generator) @@ -713,65 +714,8 @@ andMap = {-| Create a fuzzer based on the result of another fuzzer. -} andThen : (a -> Fuzzer b) -> Fuzzer a -> Fuzzer b -andThen transform (Internal.Fuzzer baseFuzzer) = - Internal.Fuzzer - (\noShrink -> - case baseFuzzer noShrink of - Gen genVal -> - Gen <| Random.andThen (transform >> Internal.unpackGenVal) genVal - - Shrink genTree -> - Shrink <| andThenRoseTrees transform genTree - - InvalidFuzzer reason -> - InvalidFuzzer reason - ) - - -andThenRoseTrees : (a -> Fuzzer b) -> Generator (RoseTree a) -> Generator (RoseTree b) -andThenRoseTrees transform genTree = - genTree - |> Random.andThen - (\(Rose root branches) -> - let - genOtherChildren : Generator (LazyList (RoseTree b)) - genOtherChildren = - branches - |> Lazy.List.map (\rt -> RoseTree.map (transform >> Internal.unpackGenTree) rt |> unwindRoseTree) - |> unwindLazyList - |> Random.map (Lazy.List.map RoseTree.flatten) - in - Random.map2 - (\(Rose trueRoot rootsChildren) otherChildren -> - Rose trueRoot (Lazy.List.append rootsChildren otherChildren) - ) - (Internal.unpackGenTree (transform root)) - genOtherChildren - ) - - -unwindRoseTree : RoseTree (Generator a) -> Generator (RoseTree a) -unwindRoseTree (Rose genRoot lazyListOfRoseTreesOfGenerators) = - case Lazy.List.headAndTail lazyListOfRoseTreesOfGenerators of - Nothing -> - Random.map RoseTree.singleton genRoot - - Just ( Rose gen children, moreList ) -> - Random.map4 (\a b c d -> Rose a (Lazy.List.cons (Rose b c) d)) - genRoot - gen - (Lazy.List.map unwindRoseTree children |> unwindLazyList) - (Lazy.List.map unwindRoseTree moreList |> unwindLazyList) - - -unwindLazyList : LazyList (Generator a) -> Generator (LazyList a) -unwindLazyList lazyListOfGenerators = - case Lazy.List.headAndTail lazyListOfGenerators of - Nothing -> - Random.constant Lazy.List.empty - - Just ( head, tail ) -> - Random.map2 Lazy.List.cons head (unwindLazyList tail) +andThen = + Fuzz.AndThen.andThen {-| Conditionally filter a fuzzer to remove occasional undesirable diff --git a/src/Fuzz/AndThen.elm b/src/Fuzz/AndThen.elm new file mode 100644 index 0000000..1c808e3 --- /dev/null +++ b/src/Fuzz/AndThen.elm @@ -0,0 +1,78 @@ +module Fuzz.AndThen exposing (andThen) + +{-| Split out the implementation of Fuzz.andThen. We are thinking about +removing it and this makes the other file easier to work with. See #161. +-} + +import Fuzz.Internal as Internal exposing (Fuzz(..), invalidReason) +import Lazy.List exposing (LazyList) +import Random.Pcg as Random exposing (Generator) +import RoseTree exposing (RoseTree(..)) + + +type alias Fuzzer a = + Internal.Fuzzer a + + +{-| Create a fuzzer based on the result of another fuzzer. +-} +andThen : (a -> Fuzzer b) -> Fuzzer a -> Fuzzer b +andThen transform (Internal.Fuzzer baseFuzzer) = + Internal.Fuzzer + (\noShrink -> + case baseFuzzer noShrink of + Gen genVal -> + Gen <| Random.andThen (transform >> Internal.unpackGenVal) genVal + + Shrink genTree -> + Shrink <| andThenRoseTrees transform genTree + + InvalidFuzzer reason -> + InvalidFuzzer reason + ) + + +andThenRoseTrees : (a -> Fuzzer b) -> Generator (RoseTree a) -> Generator (RoseTree b) +andThenRoseTrees transform genTree = + genTree + |> Random.andThen + (\(Rose root branches) -> + let + genOtherChildren : Generator (LazyList (RoseTree b)) + genOtherChildren = + branches + |> Lazy.List.map (\rt -> RoseTree.map (transform >> Internal.unpackGenTree) rt |> unwindRoseTree) + |> unwindLazyList + |> Random.map (Lazy.List.map RoseTree.flatten) + in + Random.map2 + (\(Rose trueRoot rootsChildren) otherChildren -> + Rose trueRoot (Lazy.List.append rootsChildren otherChildren) + ) + (Internal.unpackGenTree (transform root)) + genOtherChildren + ) + + +unwindRoseTree : RoseTree (Generator a) -> Generator (RoseTree a) +unwindRoseTree (Rose genRoot lazyListOfRoseTreesOfGenerators) = + case Lazy.List.headAndTail lazyListOfRoseTreesOfGenerators of + Nothing -> + Random.map RoseTree.singleton genRoot + + Just ( Rose gen children, moreList ) -> + Random.map4 (\a b c d -> Rose a (Lazy.List.cons (Rose b c) d)) + genRoot + gen + (Lazy.List.map unwindRoseTree children |> unwindLazyList) + (Lazy.List.map unwindRoseTree moreList |> unwindLazyList) + + +unwindLazyList : LazyList (Generator a) -> Generator (LazyList a) +unwindLazyList lazyListOfGenerators = + case Lazy.List.headAndTail lazyListOfGenerators of + Nothing -> + Random.constant Lazy.List.empty + + Just ( head, tail ) -> + Random.map2 Lazy.List.cons head (unwindLazyList tail)