diff --git a/elm.json b/elm.json index eac871d..2b6e70d 100644 --- a/elm.json +++ b/elm.json @@ -7,7 +7,10 @@ "exposed-modules": [ "Recursion", "Recursion.Fold", - "Recursion.Traverse" + "Recursion.Traverse", + "Recursion.Pipeline", + "Recursion.Pipeline.Fold", + "Recursion.Pipeline.Traverse" ], "elm-version": "0.19.0 <= v < 0.20.0", "dependencies": { diff --git a/src/Recursion.elm b/src/Recursion.elm index 1c143f4..4386687 100644 --- a/src/Recursion.elm +++ b/src/Recursion.elm @@ -43,6 +43,156 @@ for helpers that work with containers of recursive types. @docs runRecursion +# Converting unsafe recursions + +Converting an existing unsafe recursion to use `elm-safe-recursion` is very straightforward! There are only three steps: + +1. Make the existing function definition into lambda function and pass it as the first argument to `runRecursion` +2. Wrap each base case of your recursion in a call to `base` and change each recursive function call to be `recurse` +3. Stitch together the `Rec` types created in your calls to `recurse` using `map`, `andThen`, and other helpers from [`Recursion.Traverse`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse) and [`Recursion.Fold`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Fold) + +These steps are simple enough to describe, but there might be some art involved (especially in step #3). So let's work through some examples! + + +## Example: Fibonacci + +Note: This will not be the rightℒ️ way to implement the calculation of the fibonacci sequence. Closed form expression and memoized algorithms exist. +What we do here is take an inefficient and unsafe version and convert to an inefficient but safe version. + + +### Naive Implementation + + fib : Int -> Int + fib x = + case x of + 0 -> + 1 + + 1 -> + 1 + + _ -> + fib (x - 1) + fib (x - 2) + + +### **Step 1:** Pass our function definition to `runRecursion` + + fib : Int -> Int + fib init = + runRecursion + (\x -> + case x of + 0 -> + 1 + + 1 -> + 1 + + _ -> + fib (x - 1) + fib (x - 2) + ) + init + + +### **Step 2:** Base cases use `base` and recursive calls use `recurse` + + fib : Int -> Int + fib init = + runRecursion + (\x -> + case x of + 0 -> + base 1 + + 1 -> + base 1 + + _ -> + recurse (x - 1) + recurse (x - 2) + ) + init + + +### **Step 3:** Fix the types using `map` and `andThen` + +Our code above will generate a compiler error that looks like this: + + TYPE MISMATCH - Addition does not work with this value: + + recurse (x - 1) + recurse (x - 2) + #^^^^^^^^^^^^^^# + This `recurse` call produces: + + #Rec Int t t# + + But (+) only works with #Int# and #Float# values. + +Previously we had a recursive call to `fib` which would give us an `Int` which we could add immediately. +Now we have a `Rec` type which, similar to a `Promise` in javascript, might not actually have the value yet! + +We can use `andThen` to specify that the addition be done after the result of `recurse (x - 1)` is available. + +`recurse (x - 1) |> andThen (\fibX1 -> ...)` + +And we'll need to do a similar thing for `recurse (x - 2)` as well. + +`recurse (x - 2) |> andThen (\fibX2 -> ...)` + +If we combine these together we'll have access to both `fibX1` and `fibX2` and can add them together: + + fib : Int -> Int + fib init = + runRecursion + (\x -> + case x of + 0 -> + base 1 + + 1 -> + base 1 + + _ -> + recurse (x - 1) + |> andThen + (\fibX1 -> + recurse (x - 2) + |> map (\fibX2 -> fibX1 + fibX2) + ) + ) + init + +πŸŽ‰πŸŽ‰πŸŽ‰ And we're done! πŸŽ‰πŸŽ‰πŸŽ‰ + +Well not quite. As noted in the documentation above, due to some unfortunate implementation details, doing `recurse ... |> andThen ...` is not as efficient as it could be. +This is why the `recurseThen` function exists. + +Let's revise our code to use `recurseThen` instead: + + fib : Int -> Int + fib init = + runRecursion + (\x -> + case x of + 0 -> + base 1 + + 1 -> + base 1 + + _ -> + recurseThen (x - 1) + (\fibX1 -> + recurseThen (x - 2) + (\fibX2 -> + base (fibX1 + fibX2) + ) + ) + ) + init + +Not only faster, but even even a little easier on the eyes πŸ™ƒ + + # Example Imagine we have a generic binary tree type that we want to write a map function for: diff --git a/src/Recursion/Fold.elm b/src/Recursion/Fold.elm index 16e9201..d920fdb 100644 --- a/src/Recursion/Fold.elm +++ b/src/Recursion/Fold.elm @@ -60,6 +60,9 @@ foldList fold accum items = {-| Fold a list of items which are recurisve types and then perform a recursive action with the result. + +For a pipeable version see [`foldListPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Fold#foldListPipe). + -} foldListThen : (t -> a -> a) -> a -> List r -> (a -> Rec r t b) -> Rec r t b foldListThen fold accum items after = @@ -98,6 +101,9 @@ foldMapList foldMap accum items = {-| Fold a list of items which contain recursive types and then perform a recursive action with the result. + +For a pipeable version see [`foldMapListPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Fold#foldMapListPipe). + -} foldMapListThen : (x -> a -> Rec r t a) -> a -> List x -> (a -> Rec r t b) -> Rec r t b foldMapListThen foldMap accum items after = @@ -133,6 +139,9 @@ foldDict fold init dict = {-| Fold a `Dict` whose values are recursive types and then perform a recursive action with the result. + +For a pipeable version see [`foldDictPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Fold#foldDictPipe). + -} foldDictThen : (comparable -> t -> a -> a) -> a -> Dict comparable r -> (a -> Rec r t b) -> Rec r t b foldDictThen fold init dict after = @@ -181,6 +190,9 @@ foldMapDict foldMap init dict = {-| Fold a `Dict` whose values contain recursive types and then perform a recursive action with the result. + +For a pipeable version see [`foldMapDictPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Fold#foldMapDictPipe). + -} foldMapDictThen : (comparable -> v -> a -> Rec r t a) -> a -> Dict comparable v -> (a -> Rec r t b) -> Rec r t b foldMapDictThen foldMap init dict after = @@ -204,6 +216,9 @@ foldArray fold accum items = {-| Fold an `Array` whose items are recursive types and then perform a recursive action with the result. + +For a pipeable version see [`foldArrayPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Fold#foldArrayPipe). + -} foldArrayThen : (t -> a -> a) -> a -> Array r -> (a -> Rec r t b) -> Rec r t b foldArrayThen fold accum items after = @@ -218,6 +233,9 @@ foldMapArray foldMap accum items = {-| Fold an `Array` whose items contain recursive types and then perform a recursive action with the result. + +For a pipeable version see [`foldMapArrayPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Fold#foldMapArrayPipe). + -} foldMapArrayThen : (x -> a -> Rec r t a) -> a -> Array x -> (a -> Rec r t b) -> Rec r t b foldMapArrayThen foldMap accum items after = diff --git a/src/Recursion/Pipeline.elm b/src/Recursion/Pipeline.elm new file mode 100644 index 0000000..c10ae09 --- /dev/null +++ b/src/Recursion/Pipeline.elm @@ -0,0 +1,58 @@ +module Recursion.Pipeline exposing + ( startPipe, endPipe + , basePipe, recursePipe + , toPipeable, Pipeline + ) + +{-| + +@docs startPipe, endPipe + +@docs basePipe, recursePipe + +@docs toPipeable, Pipeline + +-} + +import Recursion exposing (..) + + +{-| A type that encapuslates a recursion pipeline. +-} +type alias Pipeline a r = + (a -> r) -> r + + +{-| Begin a pipeline. +-} +startPipe : a -> Pipeline a r +startPipe = + (|>) + + +{-| Create your own pipelineable function +-} +toPipeable : ((a -> r) -> r) -> Pipeline (a -> z) r -> Pipeline z r +toPipeable thenFunc before cont = + before ((<<) cont >> thenFunc) + + +{-| A pipeable version of `base` +-} +basePipe : x -> Pipeline (x -> z) (Rec r t a) -> Pipeline z (Rec r t a) +basePipe x = + toPipeable ((|>) x) + + +{-| A pipeable version of `recurse` +-} +recursePipe : r -> Pipeline (t -> z) (Rec r t a) -> Pipeline z (Rec r t a) +recursePipe r = + toPipeable (recurseThen r) + + +{-| End a pipeline, recovering the `Rec` object. +-} +endPipe : Pipeline a (Rec r t a) -> Rec r t a +endPipe = + (|>) base diff --git a/src/Recursion/Pipeline/Fold.elm b/src/Recursion/Pipeline/Fold.elm new file mode 100644 index 0000000..e98cb0c --- /dev/null +++ b/src/Recursion/Pipeline/Fold.elm @@ -0,0 +1,72 @@ +module Recursion.Pipeline.Fold exposing + ( foldListPipe, foldMapListPipe + , foldDictPipe, foldMapDictPipe + , foldArrayPipe, foldMapArrayPipe + ) + +{-| + + +# List + +@docs foldListPipe, foldMapListPipe + + +# Dict + +@docs foldDictPipe, foldMapDictPipe + + +# Array + +@docs foldArrayPipe, foldMapArrayPipe + +-} + +import Array exposing (Array) +import Dict exposing (Dict) +import Recursion exposing (..) +import Recursion.Fold exposing (..) +import Recursion.Pipeline exposing (..) + + +{-| Pipeable version of [`foldListThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Fold#foldListThen). +-} +foldListPipe : (t -> b -> b) -> b -> List r -> Pipeline (b -> z) (Rec r t a) -> Pipeline z (Rec r t a) +foldListPipe fold accum items = + toPipeable (foldListThen fold accum items) + + +{-| Pipeable version of [`foldMapListThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Fold#foldMapListThen). +-} +foldMapListPipe : (x -> b -> Rec r t b) -> b -> List x -> Pipeline (b -> z) (Rec r t a) -> Pipeline z (Rec r t a) +foldMapListPipe foldMap accum items = + toPipeable (foldMapListThen foldMap accum items) + + +{-| Pipeable version of [`foldDictThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Fold#foldDictThen). +-} +foldDictPipe : (comparable -> t -> b -> b) -> b -> Dict comparable r -> Pipeline (b -> z) (Rec r t a) -> Pipeline z (Rec r t a) +foldDictPipe fold init dict = + toPipeable (foldDictThen fold init dict) + + +{-| Pipeable version of [`foldMapDictThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Fold#foldMapDictThen). +-} +foldMapDictPipe : (comparable -> v -> b -> Rec r t b) -> b -> Dict comparable v -> Pipeline (b -> z) (Rec r t a) -> Pipeline z (Rec r t a) +foldMapDictPipe foldMap init dict = + toPipeable (foldMapDictThen foldMap init dict) + + +{-| Pipeable version of [`foldArrayThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Fold#foldArrayThen). +-} +foldArrayPipe : (t -> b -> b) -> b -> Array r -> Pipeline (b -> z) (Rec r t a) -> Pipeline z (Rec r t a) +foldArrayPipe fold accum items = + toPipeable (foldArrayThen fold accum items) + + +{-| Pipeable version of [`foldMapArrayThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Fold#foldMapArrayThen). +-} +foldMapArrayPipe : (x -> b -> Rec r t b) -> b -> Array x -> Pipeline (b -> z) (Rec r t a) -> Pipeline z (Rec r t a) +foldMapArrayPipe foldMap accum items = + toPipeable (foldMapArrayThen foldMap accum items) diff --git a/src/Recursion/Pipeline/Traverse.elm b/src/Recursion/Pipeline/Traverse.elm new file mode 100644 index 0000000..b5876a7 --- /dev/null +++ b/src/Recursion/Pipeline/Traverse.elm @@ -0,0 +1,148 @@ +module Recursion.Pipeline.Traverse exposing + ( sequenceListPipe, traverseListPipe + , sequenceDictPipe, traverseDictPipe + , sequenceArrayPipe, traverseArrayPipe + , sequenceMaybePipe, traverseMaybePipe + , sequenceResultPipe, traverseResultPipe + ) + +{-| This module provides pipeable versions of the `sequence____Then` and `traverse____Then` functions from +[`Recursion.Traverse`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse). + + +# List + +@docs sequenceListPipe, traverseListPipe + + +# Dict + +@docs sequenceDictPipe, traverseDictPipe + + +# Array + +@docs sequenceArrayPipe, traverseArrayPipe + + +# Maybe + +@docs sequenceMaybePipe, traverseMaybePipe + + +# Result + +@docs sequenceResultPipe, traverseResultPipe + +-} + +import Array exposing (Array) +import Dict exposing (Dict) +import Recursion exposing (..) +import Recursion.Pipeline exposing (..) +import Recursion.Traverse exposing (..) + + +{-| Pipeable version of [`sequenceListThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#sequenceListThen). +-} +sequenceListPipe : + List r + -> Pipeline (List t -> z) (Rec r t a) + -> Pipeline z (Rec r t a) +sequenceListPipe items = + toPipeable (sequenceListThen items) + + +{-| Pipeable version of [`traverseListThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#traverseListThen). +-} +traverseListPipe : + (x -> Rec r t a) + -> List x + -> Pipeline (List a -> z) (Rec r t b) + -> Pipeline z (Rec r t b) +traverseListPipe project items = + toPipeable (traverseListThen project items) + + +{-| Pipeable version of [`sequenceDictThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#sequenceDictThen). +-} +sequenceDictPipe : + Dict comparable r + -> Pipeline (Dict comparable t -> z) (Rec r t a) + -> Pipeline z (Rec r t a) +sequenceDictPipe dict = + toPipeable (sequenceDictThen dict) + + +{-| Pipeable version of [`traverseDictThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#traverseDictThen). +-} +traverseDictPipe : + (comparable -> v -> Rec r t a) + -> Dict comparable v + -> Pipeline (Dict comparable a -> z) (Rec r t b) + -> Pipeline z (Rec r t b) +traverseDictPipe project dict = + toPipeable (traverseDictThen project dict) + + +{-| Pipeable version of [`sequenceArrayThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#sequenceArrayThen). +-} +sequenceArrayPipe : + Array r + -> Pipeline (Array t -> z) (Rec r t a) + -> Pipeline z (Rec r t a) +sequenceArrayPipe items = + toPipeable (sequenceArrayThen items) + + +{-| Pipeable version of [`traverseArrayThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#traverseArrayThen). +-} +traverseArrayPipe : + (x -> Rec r t a) + -> Array x + -> Pipeline (Array a -> z) (Rec r t b) + -> Pipeline z (Rec r t b) +traverseArrayPipe project items = + toPipeable (traverseArrayThen project items) + + +{-| Pipeable version of [`sequenceMaybeThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#sequenceMaybeThen). +-} +sequenceMaybePipe : + Maybe r + -> Pipeline (Maybe t -> z) (Rec r t a) + -> Pipeline z (Rec r t a) +sequenceMaybePipe maybe = + toPipeable (sequenceMaybeThen maybe) + + +{-| Pipeable version of [`traverseMaybeThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#traverseMaybeThen). +-} +traverseMaybePipe : + (x -> Rec r t a) + -> Maybe x + -> Pipeline (Maybe a -> z) (Rec r t b) + -> Pipeline z (Rec r t b) +traverseMaybePipe project maybe = + toPipeable (traverseMaybeThen project maybe) + + +{-| Pipeable version of [`sequenceResultThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#sequenceResultThen). +-} +sequenceResultPipe : + Result e r + -> Pipeline (Result e t -> z) (Rec r t a) + -> Pipeline z (Rec r t a) +sequenceResultPipe result = + toPipeable (sequenceResultThen result) + + +{-| Pipeable version of [`traverseResultThen`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Traverse#traverseResultThen). +-} +traverseResultPipe : + (v -> Rec r t a) + -> Result e v + -> Pipeline (Result e a -> z) (Rec r t b) + -> Pipeline z (Rec r t b) +traverseResultPipe project result = + toPipeable (traverseResultThen project result) diff --git a/src/Recursion/Traverse.elm b/src/Recursion/Traverse.elm index 5fd8b01..5dae0d9 100644 --- a/src/Recursion/Traverse.elm +++ b/src/Recursion/Traverse.elm @@ -80,6 +80,9 @@ sequenceList items = {-| Traverse a list where the elements are recursive types and then perform a recursive action on the result. + +For a pipeable version see [`sequenceListPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#sequenceListPipe). + -} sequenceListThen : List r -> (List t -> Rec r t a) -> Rec r t a sequenceListThen items after = @@ -105,6 +108,9 @@ traverseList project items = {-| Traverse a list where the elements contain recursive types and then perform a recursive action on the result. + +For a pipeable version see [`traverseListPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#traverseListPipe). + -} traverseListThen : (x -> Rec r t a) -> List x -> (List a -> Rec r t b) -> Rec r t b traverseListThen project items after = @@ -145,6 +151,9 @@ sequenceDict dict = {-| Traverse a `Dict` where the values are recursive types and then perform a recursive action on the result. + +For a pipeable version see [`sequenceDictPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#sequenceDictPipe). + -} sequenceDictThen : Dict comparable r -> (Dict comparable t -> Rec r t a) -> Rec r t a sequenceDictThen dict after = @@ -168,6 +177,9 @@ traverseDict project dict = {-| Traverse a `Dict` where the values contain recursive types and then perform a recursive action the result. + +For a pipeable version see [`traverseDictPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#traverseDictPipe). + -} traverseDictThen : (comparable -> v -> Rec r t a) -> Dict comparable v -> (Dict comparable a -> Rec r t b) -> Rec r t b traverseDictThen project dict after = @@ -191,6 +203,9 @@ sequenceArray items = {-| Traverse an `Array` where the values are recursive types and then perform a recursive action on the result. + +For a pipeable version see [`sequenceArrayPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#sequenceArrayPipe). + -} sequenceArrayThen : Array r -> (Array t -> Rec r t a) -> Rec r t a sequenceArrayThen items after = @@ -205,6 +220,9 @@ traverseArray project items = {-| Traverse an `Array` where the values contain recursive types and then perform a recursive action on the result. + +For a pipeable version see [`traverseArrayPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#traverseArrayPipe). + -} traverseArrayThen : (x -> Rec r t a) -> Array x -> (Array a -> Rec r t b) -> Rec r t b traverseArrayThen project items after = @@ -230,6 +248,9 @@ sequenceMaybe maybe = {-| Traverse a `Maybe` where the value might be a recursive type and then perform a recursive action on the result. + +For a pipeable version see [`sequenceMaybePipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#sequenceMaybePipe). + -} sequenceMaybeThen : Maybe r -> (Maybe t -> Rec r t a) -> Rec r t a sequenceMaybeThen maybe after = @@ -261,6 +282,9 @@ traverseMaybe project maybe = {-| Traverse a `Maybe` where the value might contain a recursive type and then perform a recursive action on the result. + +For a pipeable version see [`traverseMaybePipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#traverseMaybePipe). + -} traverseMaybeThen : (x -> Rec r t a) -> Maybe x -> (Maybe a -> Rec r t b) -> Rec r t b traverseMaybeThen project maybe after = @@ -280,6 +304,9 @@ sequenceResult result = {-| Traverse a `Result` where the success value might be a recursive type and then perform an action on the recursive result. + +For a pipeable version see [`sequenceResultPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#sequenceResultPipe). + -} sequenceResultThen : Result e r -> (Result e t -> Rec r t a) -> Rec r t a sequenceResultThen result after = @@ -304,6 +331,9 @@ traverseResult project result = {-| Traverse a `Result` where the success value might contain a recursive type and then perform an action on the recursive result. + +For a pipeable version see [`traverseResultPipe`](https://package.elm-lang.org/packages/micahhahn/elm-safe-recursion/2.0.0/Recursion-Pipeline-Traverse#traverseResultPipe). + -} traverseResultThen : (v -> Rec r t a) -> Result e v -> (Result e a -> Rec r t b) -> Rec r t b traverseResultThen project result after = diff --git a/tests/Recursion/PipelineTest.elm b/tests/Recursion/PipelineTest.elm new file mode 100644 index 0000000..14a5bfb --- /dev/null +++ b/tests/Recursion/PipelineTest.elm @@ -0,0 +1,59 @@ +module Recursion.PipelineTest exposing (suite) + +import Expect +import Recursion exposing (..) +import Recursion.Pipeline exposing (..) +import Test exposing (..) + + +fibNaive : Int -> Int +fibNaive x = + case x of + 0 -> + 1 + + 1 -> + 1 + + _ -> + fibNaive (x - 1) + fibNaive (x - 2) + + +fib : Int -> Int +fib = + runRecursion <| + \x -> + case x of + 0 -> + base 1 + + 1 -> + base 1 + + _ -> + startPipe (+) + |> recursePipe (x - 1) + |> recursePipe (x - 2) + |> endPipe + + +correctnessTests : Test +correctnessTests = + describe "Correctenss" + [ test "fib returns same answers as naive algorithm" <| + \_ -> + let + naive = + List.range 1 10 |> List.map fibNaive + + fibs = + List.range 1 10 |> List.map fib + in + Expect.equalLists naive fibs + ] + + +suite : Test +suite = + describe "Recursion.Pipeline" + [ correctnessTests ]