├── .github └── workflows │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── bower.json ├── package.json ├── packages.dhall ├── spago.dhall ├── src └── Type │ └── Data │ └── List.purs ├── test └── Main.purs └── tests.dhall /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Build Package & Examples 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | 11 | - uses: purescript-contrib/setup-purescript@main 12 | 13 | - name: Cache PureScript dependencies 14 | uses: actions/cache@v2 15 | with: 16 | key: spago-${{ hashFiles('**/*.dhall') }} 17 | path: | 18 | .spago 19 | output 20 | 21 | - run: spago build 22 | 23 | - run: spago -x tests.dhall test 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components/ 2 | /node_modules/ 3 | /.pulp-cache/ 4 | /output/ 5 | /generated-docs/ 6 | /.psc-package/ 7 | /.psc* 8 | /.purs* 9 | /.psa* 10 | /.spago 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | Breaking changes: 9 | 10 | New features: 11 | 12 | Bugfixes: 13 | 14 | Other improvements: 15 | 16 | ## [2.1.0](https://github.com/PureFunctor/purescript-typelevel-lists/releases/tag/v2.1.0) 17 | New features: 18 | * Allowed `Map` operations to have a different resulting kind. 19 | * Replaced the `func` type variable in `Map` with a higher-kinded type `(k -> l)`, in `Fold` and 20 | `Foldr` with `(k -> k -> k)`. 21 | 22 | Other improvements: 23 | * Reworded [CHANGELOG.md](./CHANGELOG.md) to use a more concise format. 24 | * Shortened export list in `Type.Data.List` using a module export. 25 | 26 | ## [2.0.0](https://github.com/PureFunctor/purescript-typelevel-lists/releases/tag/v2.0.0) 27 | Breaking changes: 28 | * Added the `k` parameter for `List'`, enforcing homogeneity of kinds. 29 | 30 | New features: 31 | * Added the `Foldr` type class. 32 | * Added type class methods for operating on lists, with examples in the [test](./test) directory. 33 | 34 | Other improvements: 35 | * Fixed dependency warnings emitted by Spago 0.20.0 36 | * Removed example code in favor of testing type class methods. 37 | 38 | ## [1.1.0](https://github.com/PureFunctor/purescript-typelevel-lists/releases/tag/v1.1.0) 39 | New features: 40 | * Added the `Zip`, `Map`, and `Fold` type classes. 41 | 42 | Other improvements: 43 | * Reworded documentation to remove references to `Item'`. 44 | 45 | ## [1.0.0](https://github.com/PureFunctor/purescript-typelevel-lists/releases/tag/v1.0.0) 46 | Breaking changes: 47 | * Migrated from PureScript 0.13.x to PureScript 0.14.x, refactoring deprecated syntax. 48 | * Removed the `Item'` kind and the `ItemProxy` data type. 49 | 50 | ## [0.3.x](https://github.com/PureFunctor/purescript-typelevel-lists/releases/tag/v0.3.1) 51 | New features: 52 | * List and item kinds, proxies, and associated operations; compiles on PureScript 0.13.x. 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, PureFunctor 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # purescript-typelevel-lists 2 | Type-level list of kinds for PureScript. 3 | 4 | ## Documentation 5 | * Module documentation is published in [Pursuit](https://pursuit.purescript.org/packages/purescript-typelevel-lists). 6 | * Changes per release are listed on [CHANGELOG.md](./CHANGELOG.md). 7 | * Example code can be found in the [test](./test) directory. 8 | 9 | ## Installation 10 | ```sh 11 | $ spago install typelevel-lists 12 | ``` 13 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-typelevel-lists", 3 | "license": [ 4 | "BSD-3-Clause" 5 | ], 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/PureFunctor/purescript-typelevel-lists" 9 | }, 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "output" 15 | ], 16 | "dependencies": { 17 | "purescript-prelude": "^v5.0.1", 18 | "purescript-tuples": "^v6.0.1", 19 | "purescript-typelevel-peano": "^v1.0.1", 20 | "purescript-typelevel-prelude": "^v6.0.0", 21 | "purescript-unsafe-coerce": "^v5.0.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-typelevel-lists", 3 | "version": "0.0.1", 4 | "description": "Type-level heterogenous list of kinds for PureScript.", 5 | "scripts": { 6 | "repl": "spago -x examples/examples.dhall repl" 7 | }, 8 | "repository": "git@github.com:PureFunctor/purescript-typelevel-lists.git", 9 | "author": "PureFunctor ", 10 | "license": "BSD-3-Clause" 11 | } 12 | -------------------------------------------------------------------------------- /packages.dhall: -------------------------------------------------------------------------------- 1 | {- 2 | Welcome to your new Dhall package-set! 3 | 4 | Below are instructions for how to edit this file for most use 5 | cases, so that you don't need to know Dhall to use it. 6 | 7 | ## Warning: Don't Move This Top-Level Comment! 8 | 9 | Due to how `dhall format` currently works, this comment's 10 | instructions cannot appear near corresponding sections below 11 | because `dhall format` will delete the comment. However, 12 | it will not delete a top-level comment like this one. 13 | 14 | ## Use Cases 15 | 16 | Most will want to do one or both of these options: 17 | 1. Override/Patch a package's dependency 18 | 2. Add a package not already in the default package set 19 | 20 | This file will continue to work whether you use one or both options. 21 | Instructions for each option are explained below. 22 | 23 | ### Overriding/Patching a package 24 | 25 | Purpose: 26 | - Change a package's dependency to a newer/older release than the 27 | default package set's release 28 | - Use your own modified version of some dependency that may 29 | include new API, changed API, removed API by 30 | using your custom git repo of the library rather than 31 | the package set's repo 32 | 33 | Syntax: 34 | where `entityName` is one of the following: 35 | - dependencies 36 | - repo 37 | - version 38 | ------------------------------- 39 | let upstream = -- 40 | in upstream 41 | with packageName.entityName = "new value" 42 | ------------------------------- 43 | 44 | Example: 45 | ------------------------------- 46 | let upstream = -- 47 | in upstream 48 | with halogen.version = "master" 49 | with halogen.repo = "https://example.com/path/to/git/repo.git" 50 | 51 | with halogen-vdom.version = "v4.0.0" 52 | ------------------------------- 53 | 54 | ### Additions 55 | 56 | Purpose: 57 | - Add packages that aren't already included in the default package set 58 | 59 | Syntax: 60 | where `` is: 61 | - a tag (i.e. "v4.0.0") 62 | - a branch (i.e. "master") 63 | - commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977") 64 | ------------------------------- 65 | let upstream = -- 66 | in upstream 67 | with new-package-name = 68 | { dependencies = 69 | [ "dependency1" 70 | , "dependency2" 71 | ] 72 | , repo = 73 | "https://example.com/path/to/git/repo.git" 74 | , version = 75 | "" 76 | } 77 | ------------------------------- 78 | 79 | Example: 80 | ------------------------------- 81 | let upstream = -- 82 | in upstream 83 | with benchotron = 84 | { dependencies = 85 | [ "arrays" 86 | , "exists" 87 | , "profunctor" 88 | , "strings" 89 | , "quickcheck" 90 | , "lcg" 91 | , "transformers" 92 | , "foldable-traversable" 93 | , "exceptions" 94 | , "node-fs" 95 | , "node-buffer" 96 | , "node-readline" 97 | , "datetime" 98 | , "now" 99 | ] 100 | , repo = 101 | "https://github.com/hdgarrood/purescript-benchotron.git" 102 | , version = 103 | "v7.0.0" 104 | } 105 | ------------------------------- 106 | -} 107 | let upstream = 108 | https://github.com/purescript/package-sets/releases/download/psc-0.14.5-20211116/packages.dhall sha256:7ba810597a275e43c83411d2ab0d4b3c54d0b551436f4b1632e9ff3eb62e327a 109 | 110 | in upstream 111 | -------------------------------------------------------------------------------- /spago.dhall: -------------------------------------------------------------------------------- 1 | { name = "typelevel-lists" 2 | , dependencies = 3 | [ "prelude" 4 | , "tuples" 5 | , "typelevel-peano" 6 | , "typelevel-prelude" 7 | , "unsafe-coerce" 8 | ] 9 | , packages = ./packages.dhall 10 | , sources = [ "src/**/*.purs" ] 11 | , license = "BSD-3-Clause" 12 | , repository = "https://github.com/PureFunctor/purescript-typelevel-lists" 13 | } 14 | -------------------------------------------------------------------------------- /src/Type/Data/List.purs: -------------------------------------------------------------------------------- 1 | -- | Type-level heterogenous list of kinds for PureScript 2 | module Type.Data.List 3 | ( module Type.Data.List 4 | ) 5 | where 6 | 7 | 8 | import Data.Tuple (Tuple) 9 | import Data.Unit (unit) 10 | import Prim.Boolean (True, False) 11 | import Type.Data.Peano as Peano 12 | import Type.Prelude (Proxy(..)) 13 | import Unsafe.Coerce (unsafeCoerce) 14 | 15 | 16 | -- | Represents a type-level list. 17 | data List' :: forall k. k -> Type 18 | data List' k 19 | 20 | 21 | -- | Represents an empty `List'`. 22 | foreign import data Nil' :: forall k. List' k 23 | 24 | 25 | -- | Prepends an item to a `List'`, creating a new `List'`. 26 | foreign import data Cons' :: forall k. k -> List' k -> List' k 27 | 28 | 29 | infixr 1 type Cons' as :> 30 | 31 | 32 | -- | Performs membership testing given an item and a `List'`. 33 | class IsMember :: forall k. k -> List' k -> Boolean -> Constraint 34 | class IsMember x xs r | x xs -> r where 35 | isMember :: forall lproxy. Proxy x -> lproxy xs -> Boolean 36 | 37 | 38 | instance isMemberNil :: IsMember x Nil' False where 39 | isMember _ _ = false 40 | 41 | else instance isMemberNext :: IsMember x (x :> xs) True where 42 | isMember _ _ = true 43 | 44 | else instance isMemberRec 45 | :: IsMember x ys r 46 | => IsMember x (y :> ys) r where 47 | isMember x _ = isMember x (Proxy :: _ ys) 48 | 49 | 50 | -- | Concatenates two `List'`s together. 51 | class Concat :: forall k. List' k -> List' k -> List' k -> Constraint 52 | class Concat xs ys zs | xs ys -> zs where 53 | concat :: forall lproxy. lproxy xs -> lproxy ys -> lproxy zs 54 | 55 | 56 | instance concatNil :: Concat Nil' ys ys where 57 | concat _ _ = unsafeCoerce unit 58 | 59 | else instance concatRec 60 | :: Concat xs ys zs 61 | => Concat (x :> xs) ys (x :> zs) where 62 | concat _ _ = unsafeCoerce unit 63 | 64 | 65 | -- | Determines whether `List'` is empty. 66 | class IsEmpty :: forall k. List' k -> Boolean -> Constraint 67 | class IsEmpty xs r | xs -> r where 68 | isEmpty :: forall lproxy. lproxy xs -> Boolean 69 | 70 | 71 | instance nilIsEmpty :: IsEmpty Nil' True where 72 | isEmpty _ = true 73 | 74 | else instance listIsEmpty :: IsEmpty (x :> xs) False where 75 | isEmpty _ = false 76 | 77 | 78 | -- | Internal type class that acts as an accumulator. 79 | class Init' :: forall k. k -> List' k -> List' k -> Constraint 80 | class Init' xs ys zs | xs ys -> zs 81 | 82 | 83 | instance initBase :: Init' xs Nil' Nil' 84 | 85 | else instance initRec 86 | :: Init' z zs ws 87 | => Init' y (z :> zs) (y :> ws) 88 | 89 | 90 | -- | Takes the `init` items of a `List'`. 91 | class Init :: forall k. List' k -> List' k -> Constraint 92 | class Init xs ys | xs -> ys where 93 | init :: forall lproxy. lproxy xs -> lproxy ys 94 | 95 | 96 | instance initList 97 | :: Init' x xs ys 98 | => Init (x :> xs) ys where 99 | init _ = unsafeCoerce unit 100 | 101 | 102 | -- | Returns the last item of a `List'`. 103 | class Last :: forall k. List' k -> k -> Constraint 104 | class Last xs x | xs -> x where 105 | last :: forall lproxy. lproxy xs -> Proxy x 106 | 107 | 108 | instance lastBase :: Last (x :> Nil') x where 109 | last _ = Proxy 110 | 111 | else instance lastRec 112 | :: Last xs ys 113 | => Last (x :> xs) ys where 114 | last _ = Proxy 115 | 116 | 117 | -- | Internal type that acts as an accumulator 118 | class Length' :: forall k. List' k -> Peano.Int -> Peano.Int -> Constraint 119 | class Length' xs n r | xs n -> r 120 | 121 | 122 | instance lengthBase :: Length' Nil' n n 123 | 124 | else instance lengthRec 125 | :: ( Peano.SumInt n Peano.P1 m 126 | , Length' xs m r 127 | ) 128 | => Length' (x :> xs) n r 129 | 130 | 131 | -- | Computes the length of a `List'` as a `Type.Data.Peano.Int` 132 | class Length :: forall k. List' k -> Peano.Int -> Constraint 133 | class Length xs r | xs -> r where 134 | length :: forall lproxy iproxy. lproxy xs -> iproxy r 135 | 136 | 137 | instance lengthList 138 | :: Length' xs Peano.P0 r 139 | => Length xs r where 140 | length _ = unsafeCoerce unit 141 | 142 | 143 | -- | Takes an `n` amount of items from a `List'`. 144 | class Take :: forall k. Peano.Int -> List' k -> List' k -> Constraint 145 | class Take n xs ys | n xs -> ys where 146 | take :: forall lproxy iproxy. iproxy n -> lproxy xs -> lproxy ys 147 | 148 | 149 | instance takeZero :: Take Peano.P0 xs Nil' where 150 | take _ _ = unsafeCoerce unit 151 | 152 | else instance takeNil :: Take n Nil' Nil' where 153 | take _ _ = unsafeCoerce unit 154 | 155 | else instance takeRec 156 | :: ( Peano.SumInt n Peano.N1 m 157 | , Take m xs ys 158 | ) 159 | => Take n (x :> xs) (x :> ys) where 160 | take _ _ = unsafeCoerce unit 161 | 162 | 163 | -- | Drops an `n` amount of items from a `List'`. 164 | class Drop :: forall k. Peano.Int -> List' k -> List' k -> Constraint 165 | class Drop n xs ys | n xs -> ys where 166 | drop :: forall lproxy iproxy. iproxy n -> lproxy xs -> lproxy ys 167 | 168 | 169 | instance dropZero :: Drop Peano.P0 xs xs where 170 | drop _ _ = unsafeCoerce unit 171 | 172 | else instance dropNil :: Drop n Nil' Nil' where 173 | drop _ _ = unsafeCoerce unit 174 | 175 | else instance dropRec 176 | :: ( Peano.SumInt n Peano.N1 m 177 | , Drop m xs ys 178 | ) 179 | => Drop n (x :> xs) ys where 180 | drop _ _ = unsafeCoerce unit 181 | 182 | 183 | -- | Zips together two `List'`s. 184 | class Zip :: forall k. List' k -> List' k -> List' k -> Constraint 185 | class Zip x y z | x y -> z where 186 | zip :: forall lproxy. lproxy x -> lproxy y -> lproxy z 187 | 188 | 189 | instance zipLhsNil :: Zip Nil' y Nil' where 190 | zip _ _ = unsafeCoerce unit 191 | 192 | else instance zipRhsNil :: Zip x Nil' Nil' where 193 | zip _ _ = unsafeCoerce unit 194 | 195 | else instance zipRec 196 | :: Zip xs ys zs 197 | => Zip ( x :> xs ) ( y :> ys ) ( Tuple x y :> zs ) where 198 | zip _ _ = unsafeCoerce unit 199 | 200 | 201 | -- | Maps a type constructor to a `List'`. 202 | class Map :: forall k l. (k -> l) -> List' k -> List' l -> Constraint 203 | class Map f xs ys | f xs -> ys where 204 | map :: forall fproxy kproxy lproxy. fproxy f -> kproxy xs -> lproxy ys 205 | 206 | 207 | instance mapNil :: Map f Nil' Nil' where 208 | map _ _ = unsafeCoerce unit 209 | 210 | else instance mapRec 211 | :: Map f xs ys 212 | => Map f ( x :> xs ) ( f x :> ys ) where 213 | map _ _ = unsafeCoerce unit 214 | 215 | 216 | -- | Folds a `List'` into a singular value, left-associative. 217 | class Fold :: forall k. (k -> k -> k) -> k -> List' k -> k -> Constraint 218 | class Fold f z xs r | f z xs -> r where 219 | fold :: forall fproxy kproxy lproxy. fproxy f -> kproxy z -> lproxy xs -> kproxy r 220 | 221 | 222 | instance foldNil :: Fold f z Nil' z where 223 | fold _ _ _ = unsafeCoerce unit 224 | 225 | else instance foldRec 226 | :: Fold f ( f z x ) xs r 227 | => Fold f z ( x :> xs ) r where 228 | fold _ _ _ = unsafeCoerce unit 229 | 230 | 231 | -- | Folds a `List'` into a singular value, right-associative. 232 | class Foldr :: forall k. (k -> k -> k) -> k -> List' k -> k -> Constraint 233 | class Foldr f z xs r | f z xs -> r where 234 | foldr :: forall fproxy kproxy lproxy. fproxy f -> kproxy z -> lproxy xs -> kproxy r 235 | 236 | 237 | instance foldrNil :: Foldr f z Nil' z where 238 | foldr _ _ _ = unsafeCoerce unit 239 | 240 | else instance foldrOne :: Foldr f z ( x :> Nil' ) ( f x z ) where 241 | foldr _ _ _ = unsafeCoerce unit 242 | 243 | else instance foldrRec 244 | :: Foldr f z xs r 245 | => Foldr f z ( x :> xs ) ( f x r ) where 246 | foldr _ _ _ = unsafeCoerce unit 247 | 248 | 249 | -- | A value-level proxy for `List'` 250 | data ListProxy :: forall k. List' k -> Type 251 | data ListProxy l = ListProxy 252 | -------------------------------------------------------------------------------- /test/Main.purs: -------------------------------------------------------------------------------- 1 | module Test.Main where 2 | 3 | import Prelude 4 | 5 | import Data.Tuple (Tuple) 6 | import Effect (Effect) 7 | import Effect.Aff (launchAff_) 8 | import Test.Spec (Spec, describe, it) 9 | import Test.Spec.Assertions (shouldEqual) 10 | import Test.Spec.Reporter (consoleReporter) 11 | import Test.Spec.Runner (runSpec) 12 | import Type.Data.List (type (:>), Nil') 13 | import Type.Data.List as TL 14 | import Type.Data.Peano as P 15 | import Type.Prelude (Proxy(..)) 16 | 17 | 18 | data Literals 19 | 20 | foreign import data LiteralSymbol :: Symbol -> Literals 21 | 22 | 23 | spec :: Spec Unit 24 | spec = do 25 | let xs = Proxy :: _ ( Int :> Char :> Nil' ) 26 | 27 | describe "IsMember" do 28 | it "tests empty lists" do 29 | TL.isMember (Proxy :: _ Int) (Proxy :: _ Nil') `shouldEqual` false 30 | it "tests members" do 31 | TL.isMember (Proxy :: _ Int) xs `shouldEqual` true 32 | it "tests non-members" do 33 | TL.isMember (Proxy :: _ Boolean) xs `shouldEqual` false 34 | 35 | let ys = Proxy :: _ ( Int :> Nil' ) 36 | zs = Proxy :: _ ( Char :> Nil' ) 37 | nl = Proxy :: _ Nil' 38 | 39 | describe "Concat" do 40 | it "concatenates two lists" do 41 | TL.concat ys zs `shouldEqual` xs 42 | it "has a left unit" do 43 | TL.concat nl ys `shouldEqual` ys 44 | it "has a right unit" do 45 | TL.concat zs nl `shouldEqual` zs 46 | it "is an associative operation" do 47 | let l = ys `TL.concat` (ys `TL.concat` zs) 48 | r = (ys `TL.concat` ys) `TL.concat` zs 49 | l `shouldEqual` r 50 | 51 | describe "IsEmpty" do 52 | it "returns true on empty" do 53 | TL.isEmpty nl `shouldEqual` true 54 | it "returns false on non-empty" do 55 | TL.isEmpty xs `shouldEqual` false 56 | 57 | describe "Init" do 58 | it "returns the init items" do 59 | TL.init xs `shouldEqual` ys 60 | it "returns an empty list on singleton lists" do 61 | TL.init ys `shouldEqual` nl 62 | 63 | describe "Last" do 64 | it "returns the last item on regular lists" do 65 | TL.last xs `shouldEqual` ( Proxy :: _ Char ) 66 | it "returns the last item on singleton lists" do 67 | TL.last zs `shouldEqual` ( Proxy :: _ Char ) 68 | 69 | describe "Length" do 70 | it "returns zero on an empty list" do 71 | TL.length nl `shouldEqual` ( Proxy :: _ P.P0 ) 72 | 73 | it "returns the length of a non-empty list" do 74 | TL.length xs `shouldEqual` ( Proxy :: _ P.P2 ) 75 | 76 | describe "Take" do 77 | it "returns an empty list when given zero" do 78 | TL.take P.p0 xs `shouldEqual` nl 79 | TL.take P.p0 ys `shouldEqual` nl 80 | TL.take P.p0 nl `shouldEqual` nl 81 | it "returns an empty list for empty lists" do 82 | TL.take P.p1 nl `shouldEqual` nl 83 | it "returns a list with the first n items" do 84 | TL.take P.p1 xs `shouldEqual` ys 85 | 86 | describe "Drop" do 87 | it "returns the full list when given zero" do 88 | TL.drop P.p0 xs `shouldEqual` xs 89 | TL.drop P.p0 ys `shouldEqual` ys 90 | TL.drop P.p0 nl `shouldEqual` nl 91 | it "returns an empty list for empty lists" do 92 | TL.drop P.p1 nl `shouldEqual` nl 93 | it "returns a list without the first n items" do 94 | TL.drop P.p1 xs `shouldEqual` zs 95 | 96 | describe "Zip" do 97 | it "stops at Nil'" do 98 | TL.zip xs nl `shouldEqual` nl 99 | TL.zip nl xs `shouldEqual` nl 100 | TL.zip xs ys `shouldEqual` ( Proxy :: _ ( Tuple Int Int :> Nil' ) ) 101 | it "zips two lists together" do 102 | TL.zip ys zs `shouldEqual` ( Proxy :: _ ( Tuple Int Char :> Nil' ) ) 103 | 104 | describe "Map" do 105 | it "returns an empty list when empty" do 106 | TL.map ( Proxy :: _ Array ) nl `shouldEqual` nl 107 | it "transforms a non-empty list" do 108 | let r = Proxy :: _ ( Array Int :> Array Char :> Nil' ) 109 | TL.map ( Proxy :: _ Array ) xs `shouldEqual` r 110 | it "allows mapping into another kind" do 111 | let k = Proxy :: _ ( "hello" :> Nil' ) 112 | l = Proxy :: _ ( LiteralSymbol "hello" :> Nil' ) 113 | TL.map ( Proxy :: _ LiteralSymbol ) k `shouldEqual` l 114 | 115 | let f = ( Proxy :: _ Tuple ) 116 | a = ( Proxy :: _ String ) 117 | 118 | describe "Fold" do 119 | it "returns the accumulator when given an empty list" do 120 | TL.fold f a nl `shouldEqual` a 121 | it "performs a left-associative fold" do 122 | let r = Proxy :: _ ( Tuple ( Tuple String Int ) Char ) 123 | TL.fold f a xs `shouldEqual` r 124 | 125 | describe "Foldr" do 126 | it "returns the accumulator when given an empty list" do 127 | TL.foldr f a nl `shouldEqual` a 128 | it "performs a right-associative fold" do 129 | let r = Proxy :: _ ( Tuple Int ( Tuple Char String ) ) 130 | TL.foldr f a xs `shouldEqual` r 131 | 132 | 133 | main :: Effect Unit 134 | main = launchAff_ $ runSpec [ consoleReporter ] spec 135 | -------------------------------------------------------------------------------- /tests.dhall: -------------------------------------------------------------------------------- 1 | let conf = ./spago.dhall 2 | 3 | in conf 4 | // { dependencies = conf.dependencies # [ "aff", "effect", "spec" ] 5 | , sources = conf.sources # [ "test/**/*.purs" ] 6 | } 7 | --------------------------------------------------------------------------------