├── cabal.project ├── minlen ├── ChangeLog.md ├── Setup.hs ├── README.md ├── package.yaml ├── LICENSE ├── minlen.cabal └── src │ └── Data │ └── MinLen.hs ├── chunked-data ├── Setup.hs ├── README.md ├── ChangeLog.md ├── package.yaml ├── LICENSE ├── chunked-data.cabal └── src │ └── Data │ ├── Builder.hs │ ├── IOData.hs │ └── ChunkedZip.hs ├── classy-prelude ├── Setup.hs ├── LICENSE ├── package.yaml ├── classy-prelude.cabal ├── README.md ├── ChangeLog.md └── src │ └── ClassyPrelude.hs ├── classy-prelude-conduit ├── test │ └── Spec.hs ├── Setup.hs ├── README.md ├── ChangeLog.md ├── src │ └── ClassyPrelude │ │ └── Conduit.hs ├── package.yaml ├── LICENSE └── classy-prelude-conduit.cabal ├── classy-prelude-yesod ├── Setup.hs ├── README.md ├── ChangeLog.md ├── src │ └── ClassyPrelude │ │ └── Yesod.hs ├── package.yaml ├── LICENSE └── classy-prelude-yesod.cabal ├── mono-traversable ├── Setup.hs ├── bench │ ├── main.hs │ ├── Sorting.hs │ └── InitTails.hs ├── LICENSE ├── package.yaml ├── mono-traversable.cabal ├── src │ └── Data │ │ ├── MonoTraversable │ │ └── Unprefixed.hs │ │ └── NonNull.hs ├── ChangeLog.md └── README.md ├── mutable-containers ├── Setup.hs ├── hpc.sh ├── bench │ ├── ref.hs │ └── deque.hs ├── LICENSE ├── ChangeLog.md ├── package.yaml ├── src │ └── Data │ │ ├── Mutable │ │ ├── URef.hs │ │ ├── SRef.hs │ │ ├── PRef.hs │ │ ├── BRef.hs │ │ ├── DLList.hs │ │ ├── Deque.hs │ │ └── Class.hs │ │ └── Mutable.hs ├── mutable-containers.cabal ├── test │ └── Spec.hs └── README.md ├── mono-traversable-instances ├── Setup.hs ├── ChangeLog.md ├── README.md ├── package.yaml ├── LICENSE ├── mono-traversable-instances.cabal └── src │ └── Data │ └── MonoTraversable │ └── Instances.hs ├── .gitignore ├── stack.yaml ├── stack.yaml.lock ├── stack-new-time.yaml ├── stack-new-time.yaml.lock ├── README.md └── .github └── workflows └── tests.yml /cabal.project: -------------------------------------------------------------------------------- 1 | packages: 2 | */*.cabal 3 | -------------------------------------------------------------------------------- /minlen/ChangeLog.md: -------------------------------------------------------------------------------- 1 | ## 0.1.0.0 2 | 3 | * Initial release 4 | -------------------------------------------------------------------------------- /minlen/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /chunked-data/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /classy-prelude/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /classy-prelude-conduit/test/Spec.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -F -pgmF hspec-discover #-} 2 | -------------------------------------------------------------------------------- /classy-prelude-yesod/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /mono-traversable/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /mutable-containers/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /classy-prelude-conduit/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /mono-traversable-instances/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /classy-prelude-conduit/README.md: -------------------------------------------------------------------------------- 1 | ## classy-prelude-conduit 2 | 3 | classy-prelude together with conduit functions 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist/ 2 | *.swp 3 | .cabal-sandbox/ 4 | cabal.sandbox.config 5 | .stack-work/ 6 | tarballs/ 7 | *~ 8 | dist-newstyle/ 9 | -------------------------------------------------------------------------------- /chunked-data/README.md: -------------------------------------------------------------------------------- 1 | chunked-data 2 | ============ 3 | 4 | Typeclasses for dealing with various chunked data representations 5 | -------------------------------------------------------------------------------- /minlen/README.md: -------------------------------------------------------------------------------- 1 | ## minlen 2 | 3 | Express the minimum length of a container in its type. 4 | 5 | Originally part of mono-traversable, split out into its own package. 6 | -------------------------------------------------------------------------------- /classy-prelude-conduit/ChangeLog.md: -------------------------------------------------------------------------------- 1 | ## 1.4.0 2 | 3 | * Upgrade to classy-prelude 1.4.0 4 | * Upgrade to conduit 1.3.0 5 | 6 | ## 1.0.0 7 | 8 | * Support for mono-traversable-1.0.0 9 | -------------------------------------------------------------------------------- /mono-traversable-instances/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for mono-traversable-instances 2 | 3 | ## 0.1.1.0 4 | 5 | * Support dlist 1.0 6 | 7 | ## 0.1.0.0 8 | 9 | * Initial release 10 | -------------------------------------------------------------------------------- /mono-traversable-instances/README.md: -------------------------------------------------------------------------------- 1 | ## mono-traversable-instances 2 | 3 | Extra typeclass instances for mono-traversable 4 | 5 | Set up this way to allow mono-traversable itself to have minimal dependencies 6 | -------------------------------------------------------------------------------- /mutable-containers/hpc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | 3 | cabal configure --ghc-option=-fhpc --enable-tests 4 | rm -f *.tix *.mix 5 | cabal build 6 | ./dist/build/test/test 7 | hpc markup test 8 | hpc report test 9 | -------------------------------------------------------------------------------- /classy-prelude-yesod/README.md: -------------------------------------------------------------------------------- 1 | ## classy-prelude-yesod 2 | 3 | classy-prelude together with the Yesod web framework. This is an extension of 4 | classy-prelude-conduit, adding in commonly used functions and data types from 5 | Yesod. 6 | -------------------------------------------------------------------------------- /stack.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-18.5 2 | packages: 3 | - minlen 4 | - mono-traversable 5 | - mono-traversable-instances 6 | - chunked-data 7 | - classy-prelude 8 | - classy-prelude-conduit 9 | - classy-prelude-yesod 10 | - mutable-containers 11 | -------------------------------------------------------------------------------- /classy-prelude-yesod/ChangeLog.md: -------------------------------------------------------------------------------- 1 | ## 1.4.0 2 | 3 | * Upgrade to classy-prelude 1.4.0 4 | * Upgrade to conduit 1.3.0 5 | * Upgrade to yesod 1.6.0 6 | 7 | ## 1.1.0 8 | 9 | * Remove the reexport of `Handler` 10 | 11 | ## 1.0.0 12 | 13 | * Support for mono-traversable-1.0.0 14 | -------------------------------------------------------------------------------- /chunked-data/ChangeLog.md: -------------------------------------------------------------------------------- 1 | ## 0.3.1 2 | 3 | * Expose `ByteStringBuilder` 4 | 5 | ## 0.3.0 6 | 7 | * Move `Data.Sequences.Lazy` to `mono-traversable` 1.0.0 8 | * Move `Data.Textual.Encoding` to `mono-traversable` 1.0.0 9 | * Switch from blaze-builder to bytestring 0.10.2 or later 10 | 11 | ## 0.2.0 12 | 13 | * Move away from system-filepath 14 | -------------------------------------------------------------------------------- /mono-traversable/bench/main.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | 3 | #if MIN_VERSION_gauge(0,2,0) 4 | import Gauge 5 | #else 6 | import Gauge.Main 7 | #endif 8 | 9 | import Sorting (sortingBenchmarks) 10 | import InitTails (initTailsBenchmarks) 11 | 12 | 13 | main :: IO () 14 | main = defaultMain 15 | [ sortingBenchmarks 16 | , initTailsBenchmarks 17 | ] 18 | -------------------------------------------------------------------------------- /classy-prelude-conduit/src/ClassyPrelude/Conduit.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE NoImplicitPrelude #-} 2 | {-# LANGUAGE RankNTypes #-} 3 | {-# LANGUAGE TypeFamilies #-} 4 | {-# LANGUAGE FlexibleContexts #-} 5 | module ClassyPrelude.Conduit 6 | ( -- * Re-export 7 | module ClassyPrelude 8 | , module Conduit 9 | ) where 10 | 11 | import ClassyPrelude 12 | import Conduit hiding (throwM) 13 | -------------------------------------------------------------------------------- /stack.yaml.lock: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by Stack. 2 | # You should not edit this file by hand. 3 | # For more information, please see the documentation at: 4 | # https://docs.haskellstack.org/en/stable/lock_files 5 | 6 | packages: [] 7 | snapshots: 8 | - completed: 9 | size: 585817 10 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/5.yaml 11 | sha256: 22d24d0dacad9c1450b9a174c28d203f9bb482a2a8da9710a2f2a9f4afee2887 12 | original: lts-18.5 13 | -------------------------------------------------------------------------------- /minlen/package.yaml: -------------------------------------------------------------------------------- 1 | name: minlen 2 | version: 0.1.0.0 3 | synopsis: Express the minimum length of a container in its type 4 | description: See docs and README at 5 | category: Data 6 | author: Michael Snoyman 7 | maintainer: michael@snoyman.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | dependencies: 16 | - base >= 4.13 && <5 17 | - mono-traversable 18 | - transformers 19 | library: 20 | source-dirs: src 21 | -------------------------------------------------------------------------------- /classy-prelude-yesod/src/ClassyPrelude/Yesod.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleInstances #-} 2 | {-# LANGUAGE TypeFamilies #-} 3 | {-# OPTIONS_GHC -fno-warn-orphans #-} 4 | module ClassyPrelude.Yesod 5 | ( module X 6 | ) where 7 | 8 | import ClassyPrelude.Conduit as X hiding (delete, deleteBy, Handler (..)) 9 | import Yesod as X hiding (Header, parseTime) 10 | import Yesod.Static as X 11 | import Yesod.Feed as X 12 | import Network.HTTP.Client.Conduit as X 13 | import Network.HTTP.Types as X 14 | import Database.Persist.Sql as X (SqlBackend, SqlPersistT) 15 | import Database.Persist.Sql as X (runMigration) 16 | import Data.Default as X (Default (..)) 17 | -------------------------------------------------------------------------------- /chunked-data/package.yaml: -------------------------------------------------------------------------------- 1 | name: chunked-data 2 | version: 0.3.1 3 | synopsis: Typeclasses for dealing with various chunked data representations 4 | description: See docs and README at 5 | category: Data 6 | author: Michael Snoyman 7 | maintainer: michael@snoyman.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | dependencies: 16 | - base >= 4.13 && <5 17 | - transformers 18 | - bytestring >=0.10.2 19 | - text >=1.2 20 | - containers 21 | - vector 22 | 23 | library: 24 | source-dirs: src 25 | -------------------------------------------------------------------------------- /mono-traversable-instances/package.yaml: -------------------------------------------------------------------------------- 1 | name: mono-traversable-instances 2 | version: 0.1.1.0 3 | synopsis: Extra typeclass instances for mono-traversable 4 | description: See docs and README at 5 | category: Data 6 | author: Michael Snoyman 7 | maintainer: michael@fpcomplete.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | dependencies: 16 | - base >= 4.13 && <5 17 | - mono-traversable >=1.0 && <1.1 18 | - semigroupoids >=3.0 19 | - comonad >=3.0.3 20 | - vector-instances 21 | - dlist >=0.6 && <1.1 22 | - dlist-instances ==0.1.* 23 | - transformers 24 | - containers 25 | library: 26 | source-dirs: src 27 | -------------------------------------------------------------------------------- /stack-new-time.yaml: -------------------------------------------------------------------------------- 1 | resolver: lts-18.5 2 | skip-ghc-check: true 3 | packages: 4 | - minlen 5 | - mono-traversable 6 | - mono-traversable-instances 7 | - chunked-data 8 | - classy-prelude 9 | - classy-prelude-conduit 10 | - classy-prelude-yesod 11 | - mutable-containers 12 | 13 | extra-deps: 14 | - time-1.10@sha256:536801b30aa2ce66da07cb19847827662650907efb2af4c8bef0a6276445075f,5738 15 | - Cabal-3.4.1.0@sha256:664179b2b713dd0436d870640eb342c7758726b23bd6d85d2a6c573452d75e77,30533 16 | - directory-1.3.7.0@sha256:4d59f9714700e69d139084b47204fc91f13f31546aac39d666279996192b0d11,2940 17 | - process-1.6.13.2@sha256:a6530a5698796e29d85817f74ca3ae20d2172fb9fa52b492c2e6816e1306bfe8,2963 18 | - unix-2.7.2.2@sha256:15f5365c5995634e45de1772b9504761504a310184e676bc2ef60a14536dbef9,3496 19 | -------------------------------------------------------------------------------- /classy-prelude-yesod/package.yaml: -------------------------------------------------------------------------------- 1 | name: classy-prelude-yesod 2 | version: 1.5.0 3 | synopsis: Provide a classy prelude including common Yesod functionality. 4 | description: See docs and README at 5 | category: Control, Yesod 6 | author: Michael Snoyman 7 | maintainer: michael@snoyman.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | dependencies: 16 | - base >= 4.13 && <5 17 | - classy-prelude >=1.5.0 && <1.5.1 18 | - classy-prelude-conduit >=1.5.0 && <1.5.1 19 | - yesod >=1.2 20 | - yesod-newsfeed 21 | - yesod-static 22 | - http-types 23 | - http-conduit 24 | - persistent >=1.1 25 | - aeson 26 | - data-default 27 | library: 28 | source-dirs: src 29 | -------------------------------------------------------------------------------- /mutable-containers/bench/ref.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | {-# LANGUAGE TypeOperators #-} 3 | import Control.Monad 4 | import Gauge.Main 5 | import Data.Mutable 6 | 7 | test :: (MCState c ~ PrimState IO, RefElement c ~ Int, MutableRef c) 8 | => String 9 | -> (c -> c) 10 | -> Benchmark 11 | test name forceType = bench name $ whnfIO $ do 12 | ref <- fmap forceType $ newRef (5 :: Int) 13 | replicateM_ 500 $ do 14 | modifyRef' ref (+ 1) 15 | modifyRef' ref (subtract 1) 16 | void $ readRef ref 17 | replicateM_ 500 $ do 18 | writeRef ref (5 :: Int) 19 | void $ readRef ref 20 | {-# INLINE test #-} 21 | 22 | main :: IO () 23 | main = defaultMain 24 | [ test "IORef" asIORef 25 | , test "STRef" asSTRef 26 | , test "MutVar" asMutVar 27 | , test "URef" asURef 28 | , test "PRef" asPRef 29 | , test "SRef" asSRef 30 | , test "BRef" asBRef 31 | ] 32 | -------------------------------------------------------------------------------- /classy-prelude-conduit/package.yaml: -------------------------------------------------------------------------------- 1 | name: classy-prelude-conduit 2 | version: 1.5.0 3 | synopsis: classy-prelude together with conduit functions 4 | description: See docs and README at 5 | category: Control, Prelude 6 | author: Michael Snoyman 7 | maintainer: michael@snoyman.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | dependencies: 16 | - base >= 4.13 && <5 17 | - transformers 18 | - bytestring 19 | 20 | library: 21 | source-dirs: src 22 | ghc-options: 23 | - -Wall 24 | - -fno-warn-orphans 25 | dependencies: 26 | - conduit >=1.3 && <1.4 27 | - classy-prelude >=1.5.0 && <1.5.1 28 | - monad-control 29 | - resourcet 30 | - void 31 | 32 | tests: 33 | spec: 34 | main: Spec.hs 35 | source-dirs: test 36 | dependencies: 37 | - hspec 38 | - classy-prelude-conduit 39 | - QuickCheck 40 | - conduit 41 | build-tools: hspec-discover 42 | -------------------------------------------------------------------------------- /mutable-containers/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Michael Snoyman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /chunked-data/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 FP Complete 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /minlen/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Michael Snoyman, http://www.fpcomplete.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /classy-prelude/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /minlen/minlen.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.7. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: minlen 8 | version: 0.1.0.0 9 | synopsis: Express the minimum length of a container in its type 10 | description: See docs and README at 11 | category: Data 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman 15 | maintainer: michael@snoyman.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | Data.MinLen 30 | other-modules: 31 | Paths_minlen 32 | hs-source-dirs: 33 | src 34 | build-depends: 35 | base >=4.13 && <5 36 | , mono-traversable 37 | , transformers 38 | default-language: Haskell2010 39 | -------------------------------------------------------------------------------- /mono-traversable/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Michael Snoyman, http://www.fpcomplete.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /classy-prelude-conduit/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /classy-prelude-yesod/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Michael Snoyman, http://www.yesodweb.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /mono-traversable-instances/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Michael Snoyman, http://www.fpcomplete.com/ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /mutable-containers/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # ChangeLog for mutable-containers 2 | 3 | ## 0.3.4.1 4 | 5 | * Fix test suite compilation [#208](https://github.com/snoyberg/mono-traversable/pull/208) 6 | 7 | ## 0.3.4 8 | 9 | * Switch to gauge 10 | 11 | ## 0.3.3 12 | 13 | * Move into mono-traversable repo 14 | 15 | ## 0.3.2.1 16 | 17 | * Fix benchmark 18 | 19 | ## 0.3.2 20 | 21 | * Export IOPRef, IOSRef, IOBRef [#5](https://github.com/fpco/mutable-containers/pull/5) 22 | 23 | ## 0.3.1 24 | 25 | * Export IOURef [#4](https://github.com/fpco/mutable-containers/pull/4) 26 | 27 | ## 0.3.0 28 | 29 | * Rename `DList` to `DLList` to avoid conflict with difference lists 30 | 31 | ## 0.2.1.2 32 | 33 | * `Deque` optimizations by avoiding modulus operations completely. 34 | 35 | ## 0.2.1.1 36 | 37 | * Fix a bug in `Deque`'s new vector allocation/copy code. 38 | 39 | ## 0.2.1 40 | 41 | * Export `Prim`, `Unbox` and `Storable` 42 | * `SRef` uses `ForeignPtr` directly (slightly more efficient) 43 | 44 | ## 0.2.0 45 | 46 | * Restructure under the Data.Mutable module. 47 | 48 | ## 0.1.2.0 49 | 50 | * Added PRef 51 | 52 | ## 0.1.1.0 53 | 54 | * Added reference benchmark. 55 | * Added boxed deque and references. 56 | -------------------------------------------------------------------------------- /chunked-data/chunked-data.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.7. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: chunked-data 8 | version: 0.3.1 9 | synopsis: Typeclasses for dealing with various chunked data representations 10 | description: See docs and README at 11 | category: Data 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman 15 | maintainer: michael@snoyman.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | Data.Builder 30 | Data.ChunkedZip 31 | Data.IOData 32 | other-modules: 33 | Paths_chunked_data 34 | hs-source-dirs: 35 | src 36 | build-depends: 37 | base >=4.13 && <5 38 | , bytestring >=0.10.2 39 | , containers 40 | , text >=1.2 41 | , transformers 42 | , vector 43 | default-language: Haskell2010 44 | -------------------------------------------------------------------------------- /mutable-containers/bench/deque.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ConstraintKinds #-} 2 | {-# LANGUAGE TypeFamilies #-} 3 | {-# LANGUAGE TypeOperators #-} 4 | import Control.Monad 5 | import Gauge.Main 6 | import Data.Mutable 7 | import Data.Sequence (Seq) 8 | 9 | test :: (MCState c ~ PrimState IO, CollElement c ~ Int, MutableDeque c) 10 | => String 11 | -> (c -> c) 12 | -> Benchmark 13 | test name forceType = bench name $ whnfIO $ do 14 | let x = 5 :: Int 15 | coll <- fmap forceType newColl 16 | replicateM_ 500 $ pushFront coll x 17 | replicateM_ 500 $ pushBack coll x 18 | replicateM_ 200 $ void $ popFront coll 19 | replicateM_ 200 $ void $ popBack coll 20 | replicateM_ 500 $ do 21 | pushBack coll x 22 | pushFront coll x 23 | void $ popFront coll 24 | replicateM_ 500 $ do 25 | pushBack coll x 26 | pushFront coll x 27 | replicateM_ 500 $ do 28 | pushBack coll x 29 | void $ popFront coll 30 | {-# INLINE test #-} 31 | 32 | main :: IO () 33 | main = defaultMain 34 | [ test "IORef [Int]" (id :: IORef [Int] -> IORef [Int]) 35 | , test "IORef (Seq Int)" (id :: IORef (Seq Int) -> IORef (Seq Int)) 36 | , test "UDeque" asUDeque 37 | , test "SDeque" asSDeque 38 | , test "BDeque" asBDeque 39 | , test "DLList" asDLList 40 | ] 41 | -------------------------------------------------------------------------------- /mutable-containers/package.yaml: -------------------------------------------------------------------------------- 1 | name: mutable-containers 2 | version: 0.3.4.2 3 | synopsis: Abstractions and concrete implementations of mutable containers 4 | description: See docs and README at 5 | category: Data 6 | author: Michael Snoyman 7 | maintainer: michael@fpcomplete.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | dependencies: 16 | - base >= 4.13 && <5 17 | - containers 18 | - vector 19 | 20 | library: 21 | ghc-options: -O2 22 | source-dirs: src 23 | exposed-modules: 24 | - Data.Mutable 25 | dependencies: 26 | - primitive >=0.5.2.1 27 | - mono-traversable 28 | - ghc-prim 29 | tests: 30 | test: 31 | main: Spec.hs 32 | source-dirs: test 33 | dependencies: 34 | - mutable-containers 35 | - hspec 36 | - QuickCheck 37 | - primitive 38 | build-tools: hspec-discover 39 | benchmarks: 40 | deque: 41 | main: deque.hs 42 | source-dirs: bench 43 | ghc-options: 44 | - -Wall 45 | - -O2 46 | - -rtsopts 47 | dependencies: 48 | - mutable-containers 49 | - gauge 50 | ref: 51 | main: ref.hs 52 | source-dirs: bench 53 | ghc-options: 54 | - -Wall 55 | - -O2 56 | - -rtsopts 57 | dependencies: 58 | - mutable-containers 59 | - gauge 60 | -------------------------------------------------------------------------------- /mono-traversable-instances/mono-traversable-instances.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.7. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: mono-traversable-instances 8 | version: 0.1.1.0 9 | synopsis: Extra typeclass instances for mono-traversable 10 | description: See docs and README at 11 | category: Data 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman 15 | maintainer: michael@fpcomplete.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | Data.MonoTraversable.Instances 30 | other-modules: 31 | Paths_mono_traversable_instances 32 | hs-source-dirs: 33 | src 34 | build-depends: 35 | base >=4.13 && <5 36 | , comonad >=3.0.3 37 | , containers 38 | , dlist >=0.6 && <1.1 39 | , dlist-instances ==0.1.* 40 | , mono-traversable ==1.0.* 41 | , semigroupoids >=3.0 42 | , transformers 43 | , vector-instances 44 | default-language: Haskell2010 45 | -------------------------------------------------------------------------------- /mono-traversable/bench/Sorting.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | module Sorting (sortingBenchmarks) where 3 | 4 | #if MIN_VERSION_gauge(0,2,0) 5 | import Gauge 6 | #else 7 | import Gauge.Main 8 | #endif 9 | 10 | import Data.Sequences 11 | import Data.MonoTraversable 12 | import qualified Data.List 13 | import qualified System.Random.MWC as MWC 14 | import qualified Data.Vector as V 15 | import qualified Data.Vector.Unboxed as U 16 | import System.IO.Unsafe (unsafePerformIO) 17 | 18 | sortingBenchmarks :: Benchmark 19 | sortingBenchmarks 20 | = bgroup "Sorting" 21 | $ unsafePerformIO 22 | $ mapM mkGroup [10, 100, 1000, 10000] 23 | 24 | asVector :: V.Vector a -> V.Vector a 25 | asVector = id 26 | 27 | asUVector :: U.Vector a -> U.Vector a 28 | asUVector = id 29 | 30 | mkGroup :: Int -> IO Benchmark 31 | mkGroup size = do 32 | gen <- MWC.create 33 | inputV <- MWC.uniformVector gen size 34 | let inputL = otoList (inputV :: V.Vector Int) 35 | inputVU = fromList inputL :: U.Vector Int 36 | return $ bgroup (show size) 37 | [ bench "Data.List.sort" $ nf Data.List.sort inputL 38 | , bench "list sort" $ nf sort inputL 39 | , bench "list sort, via vector" $ nf (otoList . sort . asVector . fromList) inputL 40 | , bench "list sort, via uvector" $ nf (otoList . sort . asUVector . fromList) inputL 41 | , bench "vector sort" $ nf sort inputV 42 | , bench "uvector sort" $ nf sort inputVU 43 | ] 44 | -------------------------------------------------------------------------------- /classy-prelude-yesod/classy-prelude-yesod.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.7. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: classy-prelude-yesod 8 | version: 1.5.0 9 | synopsis: Provide a classy prelude including common Yesod functionality. 10 | description: See docs and README at 11 | category: Control, Yesod 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman 15 | maintainer: michael@snoyman.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | ClassyPrelude.Yesod 30 | other-modules: 31 | Paths_classy_prelude_yesod 32 | hs-source-dirs: 33 | src 34 | build-depends: 35 | aeson 36 | , base >=4.13 && <5 37 | , classy-prelude ==1.5.0.* 38 | , classy-prelude-conduit ==1.5.0.* 39 | , data-default 40 | , http-conduit 41 | , http-types 42 | , persistent >=1.1 43 | , yesod >=1.2 44 | , yesod-newsfeed 45 | , yesod-static 46 | default-language: Haskell2010 47 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable/URef.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | -- | Use 1-length mutable unboxed vectors for mutable references. 3 | -- 4 | -- Motivated by: and ArrayRef. 5 | module Data.Mutable.URef 6 | ( -- * Types 7 | URef 8 | , IOURef 9 | -- * Functions 10 | , asURef 11 | , MutableRef (..) 12 | ) where 13 | 14 | import Control.Monad (liftM) 15 | import Data.Mutable.Class 16 | import qualified Data.Vector.Generic.Mutable as V 17 | import qualified Data.Vector.Unboxed.Mutable as VU 18 | 19 | -- | An unboxed vector reference, supporting any monad. 20 | -- 21 | -- Since 0.2.0 22 | newtype URef s a = URef (VU.MVector s a) 23 | 24 | -- | 25 | -- Since 0.2.0 26 | asURef :: URef s a -> URef s a 27 | asURef x = x 28 | {-# INLINE asURef #-} 29 | 30 | -- | An unboxed IO vector reference. 31 | type IOURef = URef (PrimState IO) 32 | 33 | instance MutableContainer (URef s a) where 34 | type MCState (URef s a) = s 35 | instance VU.Unbox a => MutableRef (URef s a) where 36 | type RefElement (URef s a) = a 37 | 38 | newRef = liftM URef . V.replicate 1 39 | {-# INLINE newRef#-} 40 | 41 | readRef (URef v) = V.unsafeRead v 0 42 | {-# INLINE readRef #-} 43 | 44 | writeRef (URef v) = V.unsafeWrite v 0 45 | {-# INLINE writeRef #-} 46 | 47 | modifyRef (URef v) f = V.unsafeRead v 0 >>= V.unsafeWrite v 0 . f 48 | {-# INLINE modifyRef #-} 49 | 50 | modifyRef' = modifyRef 51 | {-# INLINE modifyRef' #-} 52 | -------------------------------------------------------------------------------- /classy-prelude/package.yaml: -------------------------------------------------------------------------------- 1 | name: classy-prelude 2 | version: 1.5.0.3 3 | synopsis: A typeclass-based Prelude. 4 | description: See docs and README at 5 | category: Control, Prelude 6 | author: Michael Snoyman 7 | maintainer: michael@snoyman.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | dependencies: 16 | - base >= 4.13 && <5 17 | - transformers 18 | - unordered-containers 19 | 20 | library: 21 | ghc-options: 22 | - -Wall 23 | - -fno-warn-orphans 24 | source-dirs: src 25 | dependencies: 26 | - basic-prelude >=0.7 27 | - containers >=0.4.2 28 | - text 29 | - bytestring 30 | - vector 31 | - hashable 32 | #- lifted-base >=0.2 33 | #- lifted-async >=0.3 34 | - async 35 | - mono-traversable >=1.0 36 | - mono-traversable-instances 37 | #- exceptions >=0.5 38 | - vector-instances 39 | - time >= 1.5 40 | #- time-locale-compat 41 | - chunked-data >=0.3 42 | - ghc-prim 43 | - stm 44 | - primitive 45 | - mtl 46 | - bifunctors 47 | - mutable-containers >=0.3 && <0.4 48 | - dlist >=0.7 49 | #- transformers-base 50 | #- safe-exceptions >=0.1.1 51 | - deepseq 52 | #- monad-unlift >=0.2 53 | - say 54 | - stm-chans >=3 55 | - unliftio >= 0.2.1.0 56 | 57 | tests: 58 | test: 59 | main: main.hs 60 | source-dirs: test 61 | ghc-options: -Wall 62 | dependencies: 63 | - classy-prelude 64 | - hspec >=1.3 65 | - QuickCheck 66 | - containers 67 | build-tools: hspec-discover 68 | -------------------------------------------------------------------------------- /mono-traversable/package.yaml: -------------------------------------------------------------------------------- 1 | name: mono-traversable 2 | version: 1.0.21.0 3 | synopsis: Type classes for mapping, folding, and traversing monomorphic containers 4 | description: Please see the README at 5 | category: Data 6 | author: Michael Snoyman, John Wiegley, Greg Weber 7 | maintainer: michael@snoyman.com 8 | license: MIT 9 | github: snoyberg/mono-traversable 10 | 11 | extra-source-files: 12 | - README.md 13 | - ChangeLog.md 14 | 15 | library: 16 | source-dirs: src 17 | ghc-options: -Wall 18 | dependencies: 19 | - base >= 4.13 && <5 20 | - containers >=0.5.8 21 | - unordered-containers >=0.2 22 | - hashable 23 | - bytestring >=0.9 24 | - text >=0.11 25 | - transformers >=0.3 26 | - vector >=0.10 27 | - vector-algorithms >=0.6 28 | - split >=0.2 29 | tests: 30 | test: 31 | main: Main.hs 32 | source-dirs: test 33 | ghc-options: -O0 34 | dependencies: 35 | - base 36 | - mono-traversable 37 | - bytestring 38 | - text 39 | - hspec 40 | - HUnit 41 | - transformers 42 | - vector 43 | - QuickCheck 44 | - containers 45 | - unordered-containers 46 | - foldl 47 | build-tools: hspec-discover 48 | benchmarks: 49 | all: 50 | main: main.hs 51 | source-dirs: bench 52 | ghc-options: 53 | - -Wall 54 | - -O2 55 | - -with-rtsopts=-A32m 56 | when: 57 | - condition: impl(ghc >= 8.6) 58 | ghc-options: -fproc-alignment=64 59 | dependencies: 60 | - base 61 | - gauge 62 | - mono-traversable 63 | - text 64 | - containers 65 | - bytestring 66 | - vector 67 | - mwc-random 68 | - deepseq 69 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable/SRef.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | -- | Use 1-length mutable storable vectors for mutable references. 3 | -- 4 | -- Motivated by: and ArrayRef. 5 | module Data.Mutable.SRef 6 | ( -- * Types 7 | SRef 8 | , IOSRef 9 | -- * Functions 10 | , asSRef 11 | , MutableRef (..) 12 | ) where 13 | 14 | import Data.Mutable.Class 15 | import Foreign.ForeignPtr 16 | import Foreign.Storable 17 | import Control.Monad.Primitive 18 | 19 | -- | A storable vector reference, supporting any monad. 20 | -- 21 | -- Since 0.2.0 22 | newtype SRef s a = SRef (ForeignPtr a) 23 | 24 | -- | 25 | -- Since 0.2.0 26 | asSRef :: SRef s a -> SRef s a 27 | asSRef x = x 28 | {-# INLINE asSRef #-} 29 | 30 | -- | A storable IO vector reference. 31 | type IOSRef = SRef (PrimState IO) 32 | 33 | instance MutableContainer (SRef s a) where 34 | type MCState (SRef s a) = s 35 | instance Storable a => MutableRef (SRef s a) where 36 | type RefElement (SRef s a) = a 37 | 38 | newRef x = unsafePrimToPrim $ do 39 | fptr <- mallocForeignPtr 40 | withForeignPtr fptr $ flip poke x 41 | return $! SRef fptr 42 | {-# INLINE newRef#-} 43 | 44 | readRef (SRef fptr) = unsafePrimToPrim $ withForeignPtr fptr peek 45 | {-# INLINE readRef #-} 46 | 47 | writeRef (SRef fptr) x = unsafePrimToPrim $ withForeignPtr fptr $ flip poke x 48 | {-# INLINE writeRef #-} 49 | 50 | modifyRef (SRef fptr) f = unsafePrimToPrim $ withForeignPtr fptr $ \ptr -> 51 | peek ptr >>= poke ptr . f 52 | {-# INLINE modifyRef #-} 53 | 54 | modifyRef' = modifyRef 55 | {-# INLINE modifyRef' #-} 56 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable.hs: -------------------------------------------------------------------------------- 1 | -- | Classes and concrete implementations for mutable data structures. 2 | -- 3 | -- For more information on the design of this library, see the README file, 4 | -- also available at . 5 | module Data.Mutable 6 | ( -- * Data types 7 | -- ** Single-cell mutable references 8 | PRef 9 | , IOPRef 10 | , asPRef 11 | , URef 12 | , IOURef 13 | , asURef 14 | , SRef 15 | , IOSRef 16 | , asSRef 17 | , BRef 18 | , IOBRef 19 | , asBRef 20 | -- *** Standard re-exports 21 | , IORef 22 | , asIORef 23 | , STRef 24 | , asSTRef 25 | , MutVar 26 | , asMutVar 27 | -- ** Collections/queues 28 | , Deque 29 | , UDeque 30 | , asUDeque 31 | , SDeque 32 | , asSDeque 33 | , BDeque 34 | , asBDeque 35 | , DLList 36 | , asDLList 37 | -- * Type classes 38 | , MutableContainer (..) 39 | , MutableRef (..) 40 | , MutableAtomicRef (..) 41 | , MutableCollection (..) 42 | , MutablePushFront (..) 43 | , MutablePushBack (..) 44 | , MutablePopFront (..) 45 | , MutablePopBack (..) 46 | -- * Constraint kinds 47 | , MutableQueue 48 | , MutableStack 49 | , MutableDeque 50 | -- * Convenience re-exports 51 | , PrimMonad 52 | , PrimState 53 | , RealWorld 54 | , Prim 55 | , Unbox 56 | , Storable 57 | ) where 58 | 59 | import Data.Mutable.Class 60 | import Data.Mutable.URef 61 | import Data.Mutable.SRef 62 | import Data.Mutable.PRef 63 | import Data.Mutable.BRef 64 | import Data.Mutable.Deque 65 | import Data.Mutable.DLList 66 | import Data.Vector.Unboxed (Unbox) 67 | import Data.Primitive (Prim) 68 | import Data.Vector.Storable (Storable) 69 | -------------------------------------------------------------------------------- /classy-prelude-conduit/classy-prelude-conduit.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.7. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: classy-prelude-conduit 8 | version: 1.5.0 9 | synopsis: classy-prelude together with conduit functions 10 | description: See docs and README at 11 | category: Control, Prelude 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman 15 | maintainer: michael@snoyman.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | ClassyPrelude.Conduit 30 | other-modules: 31 | Paths_classy_prelude_conduit 32 | hs-source-dirs: 33 | src 34 | ghc-options: -Wall -fno-warn-orphans 35 | build-depends: 36 | base >=4.13 && <5 37 | , bytestring 38 | , classy-prelude ==1.5.0.* 39 | , conduit ==1.3.* 40 | , monad-control 41 | , resourcet 42 | , transformers 43 | , void 44 | default-language: Haskell2010 45 | 46 | test-suite spec 47 | type: exitcode-stdio-1.0 48 | main-is: Spec.hs 49 | other-modules: 50 | Paths_classy_prelude_conduit 51 | hs-source-dirs: 52 | test 53 | build-tool-depends: 54 | hspec-discover:hspec-discover 55 | build-depends: 56 | QuickCheck 57 | , base >=4.13 && <5 58 | , bytestring 59 | , classy-prelude-conduit 60 | , conduit 61 | , hspec 62 | , transformers 63 | default-language: Haskell2010 64 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable/PRef.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE MagicHash #-} 2 | {-# LANGUAGE TypeFamilies #-} 3 | -- | Use @ByteArray@s containing one element for mutable references. 4 | -- 5 | -- This is similar to @URef@s, but avoids the overhead of storing the length of 6 | -- the @Vector@, which we statically know will always be 1. This allows it to 7 | -- be a bit faster. 8 | -- 9 | -- Motivated by: and ArrayRef. 10 | module Data.Mutable.PRef 11 | ( -- * Types 12 | PRef 13 | , IOPRef 14 | -- * Functions 15 | , asPRef 16 | , MutableRef (..) 17 | ) where 18 | 19 | import Data.Mutable.Class 20 | import Data.Primitive (sizeOf) 21 | import Data.Primitive.ByteArray (MutableByteArray, newByteArray, readByteArray, 22 | writeByteArray) 23 | import Data.Primitive.Types (Prim) 24 | 25 | -- | A primitive ByteArray reference, supporting any monad. 26 | -- 27 | -- Since 0.2.0 28 | newtype PRef s a = PRef (MutableByteArray s) 29 | 30 | -- | 31 | -- Since 0.2.0 32 | asPRef :: PRef s a -> PRef s a 33 | asPRef x = x 34 | {-# INLINE asPRef #-} 35 | 36 | -- | A primitive ByteArray IO reference. 37 | type IOPRef = PRef (PrimState IO) 38 | 39 | instance MutableContainer (PRef s a) where 40 | type MCState (PRef s a) = s 41 | instance Prim a => MutableRef (PRef s a) where 42 | type RefElement (PRef s a) = a 43 | 44 | newRef x = do 45 | ba <- newByteArray (sizeOf $! x) 46 | writeByteArray ba 0 x 47 | return $! PRef ba 48 | {-# INLINE newRef #-} 49 | 50 | readRef (PRef ba) = readByteArray ba 0 51 | {-# INLINE readRef #-} 52 | 53 | writeRef (PRef ba) = writeByteArray ba 0 54 | {-# INLINE writeRef #-} 55 | 56 | modifyRef (PRef ba) f = do 57 | x <- readByteArray ba 0 58 | writeByteArray ba 0 $! f x 59 | {-# INLINE modifyRef #-} 60 | 61 | modifyRef' = modifyRef 62 | {-# INLINE modifyRef' #-} 63 | -------------------------------------------------------------------------------- /classy-prelude/classy-prelude.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.7. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: classy-prelude 8 | version: 1.5.0.3 9 | synopsis: A typeclass-based Prelude. 10 | description: See docs and README at 11 | category: Control, Prelude 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman 15 | maintainer: michael@snoyman.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | ClassyPrelude 30 | other-modules: 31 | Paths_classy_prelude 32 | hs-source-dirs: 33 | src 34 | ghc-options: -Wall -fno-warn-orphans 35 | build-depends: 36 | async 37 | , base >=4.13 && <5 38 | , basic-prelude >=0.7 39 | , bifunctors 40 | , bytestring 41 | , chunked-data >=0.3 42 | , containers >=0.4.2 43 | , deepseq 44 | , dlist >=0.7 45 | , ghc-prim 46 | , hashable 47 | , mono-traversable >=1.0 48 | , mono-traversable-instances 49 | , mtl 50 | , mutable-containers ==0.3.* 51 | , primitive 52 | , say 53 | , stm 54 | , stm-chans >=3 55 | , text 56 | , time >=1.5 57 | , transformers 58 | , unliftio >=0.2.1.0 59 | , unordered-containers 60 | , vector 61 | , vector-instances 62 | default-language: Haskell2010 63 | 64 | test-suite test 65 | type: exitcode-stdio-1.0 66 | main-is: main.hs 67 | other-modules: 68 | Paths_classy_prelude 69 | hs-source-dirs: 70 | test 71 | ghc-options: -Wall 72 | build-tool-depends: 73 | hspec-discover:hspec-discover 74 | build-depends: 75 | QuickCheck 76 | , base >=4.13 && <5 77 | , classy-prelude 78 | , containers 79 | , hspec >=1.3 80 | , transformers 81 | , unordered-containers 82 | default-language: Haskell2010 83 | -------------------------------------------------------------------------------- /stack-new-time.yaml.lock: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by Stack. 2 | # You should not edit this file by hand. 3 | # For more information, please see the documentation at: 4 | # https://docs.haskellstack.org/en/stable/lock_files 5 | 6 | packages: 7 | - completed: 8 | hackage: time-1.10@sha256:536801b30aa2ce66da07cb19847827662650907efb2af4c8bef0a6276445075f,5738 9 | pantry-tree: 10 | size: 6693 11 | sha256: 1591d9d1034f19cd38fbda525969f805b5ca083b45da85602cf2b04c1a82f640 12 | original: 13 | hackage: time-1.10@sha256:536801b30aa2ce66da07cb19847827662650907efb2af4c8bef0a6276445075f,5738 14 | - completed: 15 | hackage: Cabal-3.4.1.0@sha256:664179b2b713dd0436d870640eb342c7758726b23bd6d85d2a6c573452d75e77,30533 16 | pantry-tree: 17 | size: 45845 18 | sha256: 3ff649b92452af2cd492e01e0e6bbed2008471f62038b758e48fafe1fd6a724d 19 | original: 20 | hackage: Cabal-3.4.1.0@sha256:664179b2b713dd0436d870640eb342c7758726b23bd6d85d2a6c573452d75e77,30533 21 | - completed: 22 | hackage: directory-1.3.7.0@sha256:4d59f9714700e69d139084b47204fc91f13f31546aac39d666279996192b0d11,2940 23 | pantry-tree: 24 | size: 3433 25 | sha256: 88b74942886e886b22ac1f3f0f65168563df4848766f372aaf014f712d3abb9a 26 | original: 27 | hackage: directory-1.3.7.0@sha256:4d59f9714700e69d139084b47204fc91f13f31546aac39d666279996192b0d11,2940 28 | - completed: 29 | hackage: process-1.6.13.2@sha256:a6530a5698796e29d85817f74ca3ae20d2172fb9fa52b492c2e6816e1306bfe8,2963 30 | pantry-tree: 31 | size: 1543 32 | sha256: 045d10d710f046aa69ab3dd3f425b9479820809d6c3ca1596e0b995bcf49ac7a 33 | original: 34 | hackage: process-1.6.13.2@sha256:a6530a5698796e29d85817f74ca3ae20d2172fb9fa52b492c2e6816e1306bfe8,2963 35 | - completed: 36 | hackage: unix-2.7.2.2@sha256:15f5365c5995634e45de1772b9504761504a310184e676bc2ef60a14536dbef9,3496 37 | pantry-tree: 38 | size: 3536 39 | sha256: 36434ced74d679622d61b69e8d92e1bd632d9ef3e284c63094653b2e473b0553 40 | original: 41 | hackage: unix-2.7.2.2@sha256:15f5365c5995634e45de1772b9504761504a310184e676bc2ef60a14536dbef9,3496 42 | snapshots: 43 | - completed: 44 | size: 585817 45 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/5.yaml 46 | sha256: 22d24d0dacad9c1450b9a174c28d203f9bb482a2a8da9710a2f2a9f4afee2887 47 | original: lts-18.5 48 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable/BRef.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | -- | Use 1-length mutable boxed vectors for mutable references. 3 | -- 4 | -- Motivated by: and ArrayRef. 5 | module Data.Mutable.BRef 6 | ( -- * Types 7 | BRef 8 | , IOBRef 9 | -- * Functions 10 | , asBRef 11 | , MutableRef (..) 12 | ) where 13 | 14 | import Control.Monad (liftM) 15 | import Data.Monoid (Monoid, mempty) 16 | import Data.MonoTraversable (Element) 17 | import Data.Mutable.Class 18 | import Data.Sequences (IsSequence) 19 | import qualified Data.Vector.Generic.Mutable as V 20 | import qualified Data.Vector.Mutable as VB 21 | 22 | -- | A boxed vector reference, supporting any monad. 23 | -- 24 | -- Since 0.2.0 25 | newtype BRef s a = BRef (VB.MVector s a) 26 | 27 | -- | 28 | -- Since 0.2.0 29 | asBRef :: BRef s a -> BRef s a 30 | asBRef x = x 31 | {-# INLINE asBRef #-} 32 | 33 | -- | A boxed IO vector reference. 34 | type IOBRef = BRef (PrimState IO) 35 | 36 | instance MutableContainer (BRef s a) where 37 | type MCState (BRef s a) = s 38 | instance MutableRef (BRef s a) where 39 | type RefElement (BRef s a) = a 40 | 41 | newRef = liftM BRef . V.replicate 1 42 | {-# INLINE newRef#-} 43 | 44 | readRef (BRef v) = V.unsafeRead v 0 45 | {-# INLINE readRef #-} 46 | 47 | writeRef (BRef v) = V.unsafeWrite v 0 48 | {-# INLINE writeRef #-} 49 | 50 | modifyRef (BRef v) f = V.unsafeRead v 0 >>= V.unsafeWrite v 0 . f 51 | {-# INLINE modifyRef #-} 52 | 53 | modifyRef' = modifyRef 54 | {-# INLINE modifyRef' #-} 55 | 56 | instance Monoid w => MutableCollection (BRef s w) where 57 | type CollElement (BRef s w) = Element w 58 | newColl = newRef mempty 59 | {-# INLINE newColl #-} 60 | instance IsSequence seq => MutablePushFront (BRef s seq) where 61 | pushFront = pushFrontRef 62 | {-# INLINE pushFront #-} 63 | instance IsSequence seq => MutablePushBack (BRef s seq) where 64 | pushBack = pushBackRef 65 | {-# INLINE pushBack #-} 66 | instance IsSequence seq => MutablePopFront (BRef s seq) where 67 | popFront = popFrontRef 68 | {-# INLINE popFront #-} 69 | instance IsSequence seq => MutablePopBack (BRef s seq) where 70 | popBack = popBackRef 71 | {-# INLINE popBack #-} 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## mono-traversable mega-repo 2 | 3 | [![Tests](https://github.com/snoyberg/mono-traversable/actions/workflows/tests.yml/badge.svg)](https://github.com/snoyberg/mono-traversable/actions/workflows/tests.yml) 4 | 5 | This repository contains packages in the mono-traversable and classy-prelude 6 | families. Please see the individual READMEs for more details: 7 | 8 | You probably want to view [the README for mono-traversable 9 | itself](https://github.com/snoyberg/mono-traversable/tree/master/mono-traversable#readme). 10 | 11 | Additional packages in this repository: 12 | 13 | * [mono-traversable](https://github.com/snoyberg/mono-traversable/tree/master/mono-traversable#readme) 14 | providing a set of classes for dealing with monomorphic data structures (like `ByteString` and `Text`) 15 | in a similar way to how the standard libraries treat polymorphic structures like lists 16 | * [mono-traversable-instances](https://github.com/snoyberg/mono-traversable/tree/master/mono-traversable-instances#readme), 17 | containing orphans instances for mono-traversable classes 18 | * [chunked-data](https://github.com/snoyberg/mono-traversable/tree/master/chunked-data#readme), 19 | providing typeclasses for dealing with various chunked data representations 20 | * [mutable-containers](https://github.com/snoyberg/mono-traversable/tree/master/mutable-containers#readme), 21 | abstractions and concrete implementations of mutable containers 22 | * [conduit-combinators](https://github.com/snoyberg/mono-traversable/tree/master/conduit-combinators#readme), 23 | commonly used conduit functions, for both chunked and unchunked data 24 | * [classy-prelude](https://github.com/snoyberg/mono-traversable/tree/master/classy-prelude#readme), 25 | a Prelude replacement based around the above packages (and many others) 26 | * [classy-prelude-conduit](https://github.com/snoyberg/mono-traversable/tree/master/classy-prelude-conduit#readme), 27 | extends classy-prelude with [conduit support](https://github.com/snoyberg/conduit) 28 | * [classy-prelude-yesod](https://github.com/snoyberg/mono-traversable/tree/master/classy-prelude-yesod#readme), 29 | extends classy-prelude-conduit with [Yesod web framework support](http://www.yesodweb.com) 30 | * [minlen](https://github.com/snoyberg/mono-traversable/tree/master/minlen#readme), 31 | provided a newtype wrapper with type-level annotation of minimum container 32 | length. This is a generalization of the `Data.NonNull` module in `mono-traversable` 33 | -------------------------------------------------------------------------------- /classy-prelude/README.md: -------------------------------------------------------------------------------- 1 | classy-prelude 2 | ============== 3 | 4 | A better Prelude. Haskell's Prelude needs to maintain backwards compatibility and has many aspects that no longer represents best practice. The goals of classy-prelude are: 5 | 6 | * remove all partial functions 7 | * modernize data structures 8 | * generally use Text instead of String 9 | * encourage the use of appropriate data structures such as Vectors or HashMaps instead of always using lists and associated lists 10 | * reduce import lists and the need for qualified imports 11 | 12 | classy-prelude [should only be used by application developers](http://www.yesodweb.com/blog/2013/10/prelude-replacements-libraries). Library authors should consider using [mono-traversable](https://github.com/snoyberg/mono-traversable/blob/master/README.md), which classy-prelude builds upon. 13 | 14 | It is worth noting that classy-prelude [largely front-ran changes that the community made to the base Prelude in GHC 7.10](http://www.yesodweb.com/blog/2014/10/classy-base-prelude). 15 | 16 | mono-traversable 17 | ================ 18 | 19 | Most of this functionality is provided by [mono-traversable](https://github.com/snoyberg/mono-traversable). Please read the README over there. classy-prelude gets rid of the `o` prefix from mono-traversable functions. 20 | 21 | 22 | Text 23 | ==== 24 | 25 | Lots of things use `Text` instead of `String`. 26 | Note that `show` returns a `String`. 27 | To get back `Text`, use `tshow`. 28 | 29 | 30 | other functionality 31 | =================== 32 | 33 | * exceptions package 34 | * system-filepath convenience functions 35 | * whenM, unlessM 36 | * hashNub and ordNub (efficient nub implementations). 37 | 38 | 39 | Using classy-prelude 40 | ==================== 41 | 42 | * use the NoImplicitPrelude extension (you can place this in your cabal file) and `import ClassyPrelude` 43 | * use [base-noprelude](https://github.com/hvr/base-noprelude) in your project and define a Prelude module that re-exports `ClassyPrelude`. 44 | 45 | 46 | Appendix 47 | ======== 48 | 49 | * The [mono-traversable](https://github.com/snoyberg/mono-traversable) README. 50 | * [The transition to the modern design of classy-prelude](http://www.yesodweb.com/blog/2013/09/classy-mono). 51 | 52 | These blog posts contain some out-dated information but might be helpful 53 | * [So many preludes!](http://www.yesodweb.com/blog/2013/01/so-many-preludes) (January 2013) 54 | * [ClassyPrelude: The good, the bad, and the ugly](http://www.yesodweb.com/blog/2012/08/classy-prelude-good-bad-ugly) (August 2012) 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /mono-traversable/mono-traversable.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.37.0. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: mono-traversable 8 | version: 1.0.21.0 9 | synopsis: Type classes for mapping, folding, and traversing monomorphic containers 10 | description: Please see the README at 11 | category: Data 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman, John Wiegley, Greg Weber 15 | maintainer: michael@snoyman.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | Data.Containers 30 | Data.MonoTraversable 31 | Data.MonoTraversable.Unprefixed 32 | Data.NonNull 33 | Data.Sequences 34 | other-modules: 35 | Paths_mono_traversable 36 | hs-source-dirs: 37 | src 38 | ghc-options: -Wall 39 | build-depends: 40 | base >=4.13 && <5 41 | , bytestring >=0.9 42 | , containers >=0.5.8 43 | , hashable 44 | , split >=0.2 45 | , text >=0.11 46 | , transformers >=0.3 47 | , unordered-containers >=0.2 48 | , vector >=0.10 49 | , vector-algorithms >=0.6 50 | default-language: Haskell2010 51 | 52 | test-suite test 53 | type: exitcode-stdio-1.0 54 | main-is: Main.hs 55 | other-modules: 56 | Paths_mono_traversable 57 | hs-source-dirs: 58 | test 59 | ghc-options: -O0 60 | build-tool-depends: 61 | hspec-discover:hspec-discover 62 | build-depends: 63 | HUnit 64 | , QuickCheck 65 | , base 66 | , bytestring 67 | , containers 68 | , foldl 69 | , hspec 70 | , mono-traversable 71 | , text 72 | , transformers 73 | , unordered-containers 74 | , vector 75 | default-language: Haskell2010 76 | 77 | benchmark all 78 | type: exitcode-stdio-1.0 79 | main-is: main.hs 80 | other-modules: 81 | InitTails 82 | Sorting 83 | Paths_mono_traversable 84 | hs-source-dirs: 85 | bench 86 | ghc-options: -Wall -O2 -with-rtsopts=-A32m 87 | build-depends: 88 | base 89 | , bytestring 90 | , containers 91 | , deepseq 92 | , gauge 93 | , mono-traversable 94 | , mwc-random 95 | , text 96 | , vector 97 | default-language: Haskell2010 98 | if impl(ghc >= 8.6) 99 | ghc-options: -fproc-alignment=64 100 | -------------------------------------------------------------------------------- /mutable-containers/mutable-containers.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 1.12 2 | 3 | -- This file has been generated from package.yaml by hpack version 0.34.7. 4 | -- 5 | -- see: https://github.com/sol/hpack 6 | 7 | name: mutable-containers 8 | version: 0.3.4.2 9 | synopsis: Abstractions and concrete implementations of mutable containers 10 | description: See docs and README at 11 | category: Data 12 | homepage: https://github.com/snoyberg/mono-traversable#readme 13 | bug-reports: https://github.com/snoyberg/mono-traversable/issues 14 | author: Michael Snoyman 15 | maintainer: michael@fpcomplete.com 16 | license: MIT 17 | license-file: LICENSE 18 | build-type: Simple 19 | extra-source-files: 20 | README.md 21 | ChangeLog.md 22 | 23 | source-repository head 24 | type: git 25 | location: https://github.com/snoyberg/mono-traversable 26 | 27 | library 28 | exposed-modules: 29 | Data.Mutable 30 | other-modules: 31 | Data.Mutable.BRef 32 | Data.Mutable.Class 33 | Data.Mutable.Deque 34 | Data.Mutable.DLList 35 | Data.Mutable.PRef 36 | Data.Mutable.SRef 37 | Data.Mutable.URef 38 | Paths_mutable_containers 39 | hs-source-dirs: 40 | src 41 | ghc-options: -O2 42 | build-depends: 43 | base >=4.13 && <5 44 | , containers 45 | , ghc-prim 46 | , mono-traversable 47 | , primitive >=0.5.2.1 48 | , vector 49 | default-language: Haskell2010 50 | 51 | test-suite test 52 | type: exitcode-stdio-1.0 53 | main-is: Spec.hs 54 | other-modules: 55 | Paths_mutable_containers 56 | hs-source-dirs: 57 | test 58 | build-tool-depends: 59 | hspec-discover:hspec-discover 60 | build-depends: 61 | QuickCheck 62 | , base >=4.13 && <5 63 | , containers 64 | , hspec 65 | , mutable-containers 66 | , primitive 67 | , vector 68 | default-language: Haskell2010 69 | 70 | benchmark deque 71 | type: exitcode-stdio-1.0 72 | main-is: deque.hs 73 | other-modules: 74 | Paths_mutable_containers 75 | hs-source-dirs: 76 | bench 77 | ghc-options: -Wall -O2 -rtsopts 78 | build-depends: 79 | base >=4.13 && <5 80 | , containers 81 | , gauge 82 | , mutable-containers 83 | , vector 84 | default-language: Haskell2010 85 | 86 | benchmark ref 87 | type: exitcode-stdio-1.0 88 | main-is: ref.hs 89 | other-modules: 90 | Paths_mutable_containers 91 | hs-source-dirs: 92 | bench 93 | ghc-options: -Wall -O2 -rtsopts 94 | build-depends: 95 | base >=4.13 && <5 96 | , containers 97 | , gauge 98 | , mutable-containers 99 | , vector 100 | default-language: Haskell2010 101 | -------------------------------------------------------------------------------- /mono-traversable/bench/InitTails.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE RankNTypes #-} 3 | {-# LANGUAGE TypeApplications #-} 4 | {-# LANGUAGE ScopedTypeVariables #-} 5 | {-# LANGUAGE FlexibleInstances #-} 6 | {-# LANGUAGE FlexibleContexts #-} 7 | {-# LANGUAGE AllowAmbiguousTypes #-} 8 | {-# LANGUAGE TypeFamilies #-} 9 | module InitTails (initTailsBenchmarks) where 10 | 11 | #if MIN_VERSION_gauge(0,2,0) 12 | import Gauge 13 | #else 14 | import Gauge.Main 15 | #endif 16 | 17 | import Data.Sequences as Ss 18 | import Data.MonoTraversable 19 | import Type.Reflection (Typeable, typeRep) 20 | import Control.DeepSeq 21 | import Data.Foldable (foldl') 22 | import Data.Functor ((<&>)) 23 | 24 | import Data.ByteString (StrictByteString) 25 | import Data.ByteString.Lazy (LazyByteString) 26 | import qualified Data.Text as TS 27 | import qualified Data.Text.Lazy as TL 28 | import Data.Sequence (Seq) 29 | import qualified Data.Vector as V 30 | import qualified Data.Vector.Unboxed as VU 31 | import qualified Data.Vector.Storable as VS 32 | 33 | initTailsBenchmarks :: Benchmark 34 | initTailsBenchmarks = bgroup "InitTails" 35 | [ bmg @[Char] 36 | , bmg @StrictByteString 37 | , bmg @LazyByteString 38 | , bmg @TS.Text 39 | , bmg @TL.Text 40 | , bmg @(Seq Char) 41 | , bmg @(V.Vector Char) 42 | , bmg @(VU.Vector Char) 43 | , bmg @(VS.Vector Char) 44 | ] 45 | 46 | bmg :: forall seq. 47 | ( TestLabel seq 48 | , NFData seq 49 | , IsSequence seq 50 | , Num (Index seq) 51 | , Enum (Element seq) 52 | ) => Benchmark 53 | bmg = bgroup (testLabel @seq) $ bm <$> labelledLengths 54 | where 55 | bm :: (String,[Int]) -> Benchmark 56 | bm (label,lengths) = bgroup label $ 57 | [ ("weak", weakConsume) 58 | , ("deep", deepConsume) 59 | ] <&> \(wdLabel,consume) -> bench wdLabel 60 | $ nf (map $ consume . initTails @seq) 61 | $ (`Ss.replicate` (toEnum 65)) . fromIntegral <$> lengths 62 | labelledLengths = 63 | [ ("tiny", [0,1,2,5,10]) 64 | , ("small", [100,150,200,300]) 65 | , ("medium", [1000,1500,2000,2500]) 66 | , ("large", [10000,20000,50000]) 67 | ] 68 | 69 | class Typeable a => TestLabel a where 70 | testLabel :: String 71 | testLabel = show $ typeRep @a 72 | instance TestLabel [Char] 73 | instance TestLabel StrictByteString where testLabel = "StrictByteString" 74 | instance TestLabel LazyByteString where testLabel = "LazyByteString" 75 | instance TestLabel TS.Text where testLabel = "StrictText" 76 | instance TestLabel TL.Text where testLabel = "LazyText" 77 | instance TestLabel (Seq Char) where testLabel = "Seq" 78 | instance TestLabel (V.Vector Char) where testLabel = "Vector" 79 | instance TestLabel (VU.Vector Char) where testLabel = "UnboxedVector" 80 | instance TestLabel (VS.Vector Char) where testLabel = "StorableVector" 81 | 82 | 83 | -- *Consume used to keep memory usage lower 84 | deepConsume :: NFData seq => [(seq,seq)] -> () 85 | deepConsume = foldl' (\() (is,ts) -> deepseq is $ deepseq ts ()) () 86 | 87 | weakConsume :: [(seq,seq)] -> () 88 | weakConsume = foldl' (\() (_,_) -> ()) () 89 | 90 | -------------------------------------------------------------------------------- /chunked-data/src/Data/Builder.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE MultiParamTypeClasses #-} 2 | {-# LANGUAGE FunctionalDependencies #-} 3 | {-# LANGUAGE TypeFamilies #-} 4 | {-# LANGUAGE FlexibleContexts #-} 5 | -- | Abstraction for different kinds of builders. 6 | -- 7 | -- Note that whenever a character encoding is used, it will be UTF8. For 8 | -- different behavior, please use the underlying library. 9 | module Data.Builder 10 | ( TextBuilder 11 | , BlazeBuilder 12 | , ByteStringBuilder 13 | , Builder (..) 14 | , ToBuilder (..) 15 | , textToBuilder 16 | ) where 17 | 18 | import Data.Monoid (Monoid) 19 | 20 | import qualified Data.Text as T 21 | import qualified Data.Text.Lazy as TL 22 | import qualified Data.Text.Lazy.Builder as TB 23 | 24 | import qualified Data.ByteString as S 25 | import qualified Data.ByteString.Lazy as L 26 | import qualified Data.ByteString.Builder as BB 27 | import qualified Data.ByteString.Builder.Extra as BB (flush) 28 | 29 | import qualified Data.Text.Encoding as TE 30 | import qualified Data.Text.Lazy.Encoding as TLE 31 | 32 | -- | Since 0.1.0.0 33 | type TextBuilder = TB.Builder 34 | 35 | -- | Since 0.1.0.0 36 | type BlazeBuilder = BB.Builder 37 | 38 | -- | Since 0.3.0.0 39 | type ByteStringBuilder = BB.Builder 40 | 41 | -- | Since 0.1.0.0 42 | class Monoid builder => Builder builder lazy | builder -> lazy, lazy -> builder where 43 | -- | Since 0.1.0.0 44 | builderToLazy :: builder -> lazy 45 | 46 | -- | Since 0.1.0.0 47 | flushBuilder :: builder 48 | 49 | instance Builder TB.Builder TL.Text where 50 | builderToLazy = TB.toLazyText 51 | flushBuilder = TB.flush 52 | 53 | instance Builder BB.Builder L.ByteString where 54 | builderToLazy = BB.toLazyByteString 55 | flushBuilder = BB.flush 56 | 57 | -- | Since 0.1.0.0 58 | class ToBuilder value builder where 59 | -- | Since 0.1.0.0 60 | toBuilder :: value -> builder 61 | 62 | -- Text 63 | instance ToBuilder TB.Builder TB.Builder where 64 | toBuilder = id 65 | instance ToBuilder T.Text TB.Builder where 66 | toBuilder = TB.fromText 67 | instance ToBuilder TL.Text TB.Builder where 68 | toBuilder = TB.fromLazyText 69 | instance ToBuilder Char TB.Builder where 70 | toBuilder = TB.singleton 71 | instance (a ~ Char) => ToBuilder [a] TB.Builder where 72 | toBuilder = TB.fromString 73 | 74 | -- Blaze 75 | instance ToBuilder BB.Builder BB.Builder where 76 | toBuilder = id 77 | instance ToBuilder T.Text BB.Builder where 78 | toBuilder = TE.encodeUtf8Builder 79 | instance ToBuilder TL.Text BB.Builder where 80 | toBuilder = TLE.encodeUtf8Builder 81 | instance ToBuilder Char BB.Builder where 82 | toBuilder = toBuilder . T.singleton 83 | instance (a ~ Char) => ToBuilder [a] BB.Builder where 84 | toBuilder = toBuilder . TL.pack 85 | 86 | instance ToBuilder S.ByteString BB.Builder where 87 | toBuilder = BB.byteString 88 | instance ToBuilder L.ByteString BB.Builder where 89 | toBuilder = BB.lazyByteString 90 | 91 | -- | Provided for type disambiguation in the presence of OverloadedStrings. 92 | -- 93 | -- Since 0.1.0.0 94 | textToBuilder :: ToBuilder T.Text builder => T.Text -> builder 95 | textToBuilder = toBuilder 96 | -------------------------------------------------------------------------------- /classy-prelude/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # ChangeLog for classy-prelude 2 | 3 | ## 1.5.0.3 4 | 5 | * Don't import Data.Functor.unzip [#215](https://github.com/snoyberg/mono-traversable/pull/215) 6 | 7 | ## 1.5.0.2 8 | 9 | * Fix building with time >= 1.10 [#207](https://github.com/snoyberg/mono-traversable/pull/207). 10 | 11 | ## 1.5.0.1 12 | 13 | * Export a compatibility shim for `parseTime` as it has been removed in `time-1.10`. 14 | See 15 | 16 | ## 1.5.0 17 | 18 | * Removed `alwaysSTM` and `alwaysSucceedsSTM`. See 19 | 20 | 21 | ## 1.4.0 22 | 23 | * Switch to `MonadUnliftIO` 24 | 25 | ## 1.3.1 26 | 27 | * Add terminal IO functions 28 | 29 | ## 1.3.0 30 | 31 | * Tracing functions leave warnings when used 32 | 33 | ## 1.2.0.1 34 | 35 | * Use `HasCallStack` in `undefined` 36 | 37 | ## 1.2.0 38 | 39 | * Don't generalize I/O functions to `IOData`, instead specialize to 40 | `ByteString`. See: 41 | http://www.snoyman.com/blog/2016/12/beware-of-readfile#real-world-failures 42 | 43 | ## 1.0.2 44 | 45 | * Export `parseTimeM` for `time >= 1.5` 46 | 47 | ## 1.0.1 48 | 49 | * Add the `say` package reexports 50 | * Add the `stm-chans` package reexports 51 | 52 | ## 1.0.0.2 53 | 54 | * Allow basic-prelude 0.6 55 | 56 | ## 1.0.0.1 57 | 58 | * Support for safe-exceptions-0.1.4.0 59 | 60 | ## 1.0.0 61 | 62 | * Support for mono-traversable-1.0.0 63 | * Switch to safe-exceptions 64 | * Add monad-unlift and lifted-async 65 | 66 | ## 0.12.8 67 | 68 | * Add (<&&>),(<||>) [#125](https://github.com/snoyberg/classy-prelude/pull/125) 69 | 70 | ## 0.12.7 71 | 72 | * Concurrency: reexport `Control.Concurrent.Lifted` and provide `yieldThread` 73 | 74 | ## 0.12.6 75 | 76 | * Regeneralize intercalate [#119](https://github.com/snoyberg/classy-prelude/pull/119) 77 | * Add missing exports for `traverse_` and `for_` 78 | * Generalize `mapM_` and `forM_` for GHC 7.10 79 | 80 | ## 0.12.5.1 81 | 82 | * Support for QuickCheck 2.8.2 83 | 84 | ## 0.12.5 85 | 86 | * Expose `Alternative` and `optional` 87 | 88 | ## 0.12.4 89 | 90 | * Expose `traverse_` and `for_` 91 | 92 | ## 0.12.3 93 | 94 | * mono-traversable-0.9.3 support 95 | 96 | ## 0.12.2 97 | 98 | add `errorM`, `terrorM`, and `terror` 99 | 100 | ## 0.12.0 101 | 102 | * Drop system-filepath 103 | 104 | ## 0.11.1.1 105 | 106 | * Compatibility with time >= 1.5 [#100](https://github.com/snoyberg/classy-prelude/pull/100) 107 | 108 | ## 0.11.1 109 | 110 | * Fix deprecation warnings for `elem` 111 | 112 | ## 0.11.0 113 | 114 | * Upgrade to mutable-containers 0.3 115 | * Include dlist support 116 | 117 | ## 0.10.5 118 | 119 | * Export `Data.Mutable` 120 | 121 | ## 0.10.4 122 | 123 | * Expose all of Data.Functor 124 | 125 | ## 0.10.3 126 | 127 | * Expose `liftA` functions and `<**>` [#94](https://github.com/snoyberg/classy-prelude/pull/94) 128 | 129 | ## 0.10.2 130 | 131 | * Provide `foldMap` and `fold` as synonyms for `concatMap` and `concat`. 132 | * Switch to more general `Traversable`-based functions (`sequence_` in particular). 133 | -------------------------------------------------------------------------------- /chunked-data/src/Data/IOData.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE TypeFamilies #-} 3 | module Data.IOData where 4 | 5 | import Control.Monad (liftM) 6 | import Control.Monad.IO.Class 7 | import qualified Data.ByteString as ByteString 8 | import qualified Data.ByteString.Char8 as ByteString8 9 | import qualified Data.ByteString.Lazy as LByteString 10 | import Data.ByteString.Lazy.Internal (defaultChunkSize) 11 | import qualified Data.Text as Text 12 | import qualified Data.Text.IO as Text 13 | import qualified Data.Text.Lazy as LText 14 | import qualified Data.Text.Lazy.IO as LText 15 | import Prelude (Char, flip, ($), (.), FilePath) 16 | import qualified Prelude 17 | import System.IO (Handle) 18 | import qualified System.IO 19 | 20 | -- | Data which can be read to and from files and handles. 21 | -- 22 | -- Note that, for lazy sequences, these operations may perform 23 | -- lazy I\/O. 24 | class IOData a where 25 | readFile :: MonadIO m => FilePath -> m a 26 | writeFile :: MonadIO m => FilePath -> a -> m () 27 | getLine :: MonadIO m => m a 28 | hGetContents :: MonadIO m => Handle -> m a 29 | hGetLine :: MonadIO m => Handle -> m a 30 | hPut :: MonadIO m => Handle -> a -> m () 31 | hPutStrLn :: MonadIO m => Handle -> a -> m () 32 | hGetChunk :: MonadIO m => Handle -> m a 33 | instance IOData ByteString.ByteString where 34 | readFile = liftIO . ByteString.readFile 35 | writeFile fp = liftIO . ByteString.writeFile fp 36 | getLine = liftIO ByteString.getLine 37 | hGetContents = liftIO . ByteString.hGetContents 38 | hGetLine = liftIO . ByteString.hGetLine 39 | hPut h = liftIO . ByteString.hPut h 40 | hPutStrLn h = liftIO . ByteString8.hPutStrLn h 41 | hGetChunk = liftIO . flip ByteString.hGetSome defaultChunkSize 42 | instance IOData LByteString.ByteString where 43 | readFile = liftIO . LByteString.readFile 44 | writeFile fp = liftIO . LByteString.writeFile fp 45 | getLine = liftM LByteString.fromStrict (liftIO ByteString.getLine) 46 | hGetContents = liftIO . LByteString.hGetContents 47 | hGetLine = liftM LByteString.fromStrict . liftIO . ByteString.hGetLine 48 | hPut h = liftIO . LByteString.hPut h 49 | hPutStrLn h lbs = liftIO $ do 50 | LByteString.hPutStr h lbs 51 | ByteString8.hPutStrLn h ByteString.empty 52 | hGetChunk = liftM LByteString.fromStrict . hGetChunk 53 | instance IOData Text.Text where 54 | readFile = liftIO . Text.readFile 55 | writeFile fp = liftIO . Text.writeFile fp 56 | getLine = liftIO Text.getLine 57 | hGetContents = liftIO . Text.hGetContents 58 | hGetLine = liftIO . Text.hGetLine 59 | hPut h = liftIO . Text.hPutStr h 60 | hPutStrLn h = liftIO . Text.hPutStrLn h 61 | hGetChunk = liftIO . Text.hGetChunk 62 | instance IOData LText.Text where 63 | readFile = liftIO . LText.readFile 64 | writeFile fp = liftIO . LText.writeFile fp 65 | getLine = liftIO LText.getLine 66 | hGetContents = liftIO . LText.hGetContents 67 | hGetLine = liftIO . LText.hGetLine 68 | hPut h = liftIO . LText.hPutStr h 69 | hPutStrLn h = liftIO . LText.hPutStrLn h 70 | hGetChunk = liftM LText.fromStrict . hGetChunk 71 | instance (Char ~ c) => IOData [c] where 72 | readFile = liftIO . Prelude.readFile 73 | writeFile fp = liftIO . Prelude.writeFile fp 74 | getLine = liftIO Prelude.getLine 75 | hGetContents = liftIO . System.IO.hGetContents 76 | hGetLine = liftIO . System.IO.hGetLine 77 | hPut h = liftIO . System.IO.hPutStr h 78 | hPutStrLn h = liftIO . System.IO.hPutStrLn h 79 | hGetChunk = liftM Text.unpack . hGetChunk 80 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | branches: 8 | - master 9 | 10 | jobs: 11 | stack: 12 | name: Stack 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: 17 | - macos-latest 18 | - ubuntu-latest 19 | - windows-latest 20 | versions: 21 | #- 22 | - 22.28 9.6.6 23 | - 21.25 9.4.8 24 | - 20.26 9.2.8 25 | - 19.33 9.0.2 26 | - 18.28 8.10.7 27 | exclude: 28 | - os: macos-latest 29 | versions: 19.33 9.0.2 30 | - os: macos-latest 31 | versions: 18.28 8.10.7 32 | steps: 33 | - name: Parse lts and ghc versions 34 | shell: sh 35 | run: | 36 | echo snapshot=$(echo ${{ matrix.versions }} | cut -d ' ' -f 1) >> $GITHUB_ENV 37 | echo ghcVersion=$(echo ${{ matrix.versions }} | cut -d ' ' -f 2) >> $GITHUB_ENV 38 | - name: Setup Haskell 39 | id: setup-haskell-stack 40 | uses: haskell-actions/setup@v2.7 41 | with: 42 | ghc-version: ${{ env.ghcVersion }} 43 | enable-stack: true 44 | stack-version: 'latest' 45 | cabal-update: false 46 | - name: Clone project 47 | uses: actions/checkout@v4 48 | - name: Use Cache 49 | uses: actions/cache@v4 50 | with: 51 | key: ${{ matrix.os }}_${{ env.snapshot }}_${{ github.head_ref }} 52 | restore-keys: | 53 | ${{ matrix.os }}_${{ env.snapshot }}_${{ github.head_ref }} 54 | ${{ matrix.os }}_${{ env.snapshot }}_${{ github.base_ref }} 55 | ${{ matrix.os }}_${{ env.snapshot }}_ 56 | ${{ matrix.os }}_${{ env.snapshot }} 57 | path: | 58 | ${{ steps.setup-haskell-stack.outputs.stack-root }} 59 | .stack-work 60 | */.stack-work 61 | - name: Build and run tests 62 | shell: bash 63 | run: | 64 | set -ex 65 | ghc --version 66 | stack --version 67 | stack test --system-ghc $extraLibDirs $extraIncludeDirsLLVM $extraIncludeDirsFFI --fast --no-terminal --snapshot=lts-$snapshot 68 | - name: Check for Source Changes 69 | shell: bash 70 | run: | 71 | if [ -n "$(git status --porcelain)" ] 72 | then 73 | >&2 echo 'ERROR: Source Changed After Build' 74 | >&2 git diff 75 | >&2 git status 76 | >&2 echo 'ERROR: Source Changed After Build' 77 | exit 1 78 | fi 79 | 80 | Cabal: 81 | name: Cabal 82 | runs-on: ${{ matrix.os }} 83 | strategy: 84 | matrix: 85 | os: 86 | - macos-latest 87 | - macos-13 88 | - ubuntu-latest 89 | - windows-latest 90 | steps: 91 | - name: Setup Haskell 92 | id: setup-haskell-cabal 93 | uses: haskell-actions/setup@v2.7 94 | with: 95 | ghc-version: 9.6.6 96 | - name: Clone project 97 | uses: actions/checkout@v4 98 | - name: Use Cache 99 | uses: actions/cache@v4 100 | with: 101 | key: ${{ matrix.os }}_cabal_${{ github.head_ref }} 102 | restore-keys: | 103 | ${{ matrix.os }}_cabal_${{ github.head_ref }} 104 | ${{ matrix.os }}_cabal_${{ github.base_ref }} 105 | ${{ matrix.os }}_cabal_ 106 | ${{ matrix.os }}_cabal 107 | path: | 108 | ${{ steps.setup-haskell-cabal.outputs.cabal-store }} 109 | dist-newstyle 110 | - name: Build and run tests 111 | shell: bash 112 | run: | 113 | ghc --version 114 | cabal --version 115 | cabal test --minimize-conflict-set -O0 all 116 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable/DLList.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | -- | Doubly-linked list 3 | module Data.Mutable.DLList 4 | ( DLList 5 | , asDLList 6 | , module Data.Mutable.Class 7 | ) where 8 | 9 | import Data.Mutable.Class 10 | 11 | data Node s a = Node 12 | a 13 | (MutVar s (Maybe (Node s a))) -- previous 14 | (MutVar s (Maybe (Node s a))) -- next 15 | 16 | -- | A doubly-linked list. 17 | -- 18 | -- Since 0.3.0 19 | data DLList s a = DLList (MutVar s (Maybe (Node s a))) (MutVar s (Maybe (Node s a))) 20 | 21 | -- | 22 | -- Since 0.2.0 23 | asDLList :: DLList s a -> DLList s a 24 | asDLList = id 25 | {-# INLINE asDLList #-} 26 | 27 | instance MutableContainer (DLList s a) where 28 | type MCState (DLList s a) = s 29 | instance MutableCollection (DLList s a) where 30 | type CollElement (DLList s a) = a 31 | newColl = do 32 | x <- newRef $! Nothing 33 | y <- newRef $! Nothing 34 | return $! DLList x y 35 | {-# INLINE newColl #-} 36 | instance MutablePopFront (DLList s a) where 37 | popFront (DLList frontRef backRef) = do 38 | mfront <- readRef frontRef 39 | case mfront of 40 | Nothing -> return Nothing 41 | Just (Node val _ nextRef) -> do 42 | mnext <- readRef nextRef 43 | case mnext of 44 | Nothing -> do 45 | writeRef frontRef $! Nothing 46 | writeRef backRef $! Nothing 47 | Just next@(Node _ prevRef _) -> do 48 | writeRef prevRef $! Nothing 49 | writeRef frontRef $! Just next 50 | return $ Just val 51 | {-# INLINE popFront #-} 52 | instance MutablePopBack (DLList s a) where 53 | popBack (DLList frontRef backRef) = do 54 | mback <- readRef backRef 55 | case mback of 56 | Nothing -> return Nothing 57 | Just (Node val prevRef _) -> do 58 | mprev <- readRef prevRef 59 | case mprev of 60 | Nothing -> do 61 | writeRef frontRef $! Nothing 62 | writeRef backRef $! Nothing 63 | Just prev@(Node _ _ nextRef) -> do 64 | writeRef nextRef $! Nothing 65 | writeRef backRef (Just prev) 66 | return $ Just val 67 | {-# INLINE popBack #-} 68 | instance MutablePushFront (DLList s a) where 69 | pushFront (DLList frontRef backRef) val = do 70 | mfront <- readRef frontRef 71 | case mfront of 72 | Nothing -> do 73 | prevRef <- newRef $! Nothing 74 | nextRef <- newRef $! Nothing 75 | let node = Just $ Node val prevRef nextRef 76 | writeRef frontRef node 77 | writeRef backRef node 78 | Just front@(Node _ prevRef _) -> do 79 | prevRefNew <- newRef $! Nothing 80 | nextRef <- newRef $ Just front 81 | let node = Just $ Node val prevRefNew nextRef 82 | writeRef prevRef node 83 | writeRef frontRef node 84 | {-# INLINE pushFront #-} 85 | instance MutablePushBack (DLList s a) where 86 | pushBack (DLList frontRef backRef) val = do 87 | mback <- readRef backRef 88 | case mback of 89 | Nothing -> do 90 | prevRef <- newRef $! Nothing 91 | nextRef <- newRef $! Nothing 92 | let node = Just $! Node val prevRef nextRef 93 | writeRef frontRef $! node 94 | writeRef backRef $! node 95 | Just back@(Node _ _ nextRef) -> do 96 | nextRefNew <- newRef $! Nothing 97 | prevRef <- newRef $! Just back 98 | let node = Just $! Node val prevRef nextRefNew 99 | writeRef nextRef $! node 100 | writeRef backRef $! node 101 | {-# INLINE pushBack #-} 102 | -------------------------------------------------------------------------------- /mono-traversable-instances/src/Data/MonoTraversable/Instances.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE TypeFamilies #-} 3 | {-# OPTIONS_GHC -fno-warn-orphans #-} 4 | module Data.MonoTraversable.Instances () where 5 | 6 | import Data.DList.Instances () 7 | import Data.Traversable.Instances () 8 | import Data.Functor.Apply (MaybeApply (..), WrappedApplicative) 9 | import Control.Comonad (Cokleisli, Comonad, extract, extend) 10 | import Control.Comonad.Store (StoreT) 11 | import Control.Comonad.Env (EnvT) 12 | import Control.Comonad.Traced (TracedT) 13 | import Data.DList (DList) 14 | import Data.Semigroupoid.Static (Static) 15 | import qualified Data.DList as DL 16 | import Data.Vector.Instances () 17 | import Data.MonoTraversable 18 | import Data.Sequences 19 | import Control.Monad.Trans.Identity (IdentityT) 20 | import Data.Semigroup (Arg) 21 | import Data.List.NonEmpty (NonEmpty) 22 | import Data.Functor.Identity (Identity) 23 | import Data.Tree (Tree) 24 | import Data.Traversable (traverse) 25 | import Control.Applicative (Applicative) 26 | import Data.Monoid (Monoid) 27 | 28 | #if !MIN_VERSION_comonad(5,0,0) 29 | import Data.Functor.Coproduct (Coproduct) 30 | #endif 31 | 32 | type instance Element (DList a) = a 33 | instance MonoFoldable (DList a) where 34 | otoList = DL.toList 35 | headEx = DL.head 36 | {-# INLINE otoList #-} 37 | {-# INLINE headEx #-} 38 | instance MonoTraversable (DList a) where 39 | otraverse f = fmap DL.fromList . Data.Traversable.traverse f . DL.toList 40 | instance MonoFunctor (DList a) 41 | instance MonoPointed (DList a) 42 | instance GrowingAppend (DList a) 43 | 44 | instance SemiSequence (DList a) where 45 | type Index (DList a) = Int 46 | cons = DL.cons 47 | snoc = DL.snoc 48 | 49 | reverse = defaultReverse 50 | sortBy = defaultSortBy 51 | intersperse = defaultIntersperse 52 | find = defaultFind 53 | {-# INLINE intersperse #-} 54 | {-# INLINE reverse #-} 55 | {-# INLINE find #-} 56 | {-# INLINE sortBy #-} 57 | {-# INLINE cons #-} 58 | {-# INLINE snoc #-} 59 | 60 | instance IsSequence (DList a) where 61 | fromList = DL.fromList 62 | replicate = DL.replicate 63 | #if MIN_VERSION_dlist(1,0,0) 64 | tailEx = DL.fromList . DL.tail 65 | #else 66 | tailEx = DL.tail 67 | #endif 68 | {-# INLINE fromList #-} 69 | {-# INLINE replicate #-} 70 | {-# INLINE tailEx #-} 71 | 72 | type instance Element (Cokleisli w a b) = b 73 | instance MonoFunctor (Cokleisli w a b) 74 | instance MonoPointed (Cokleisli w a b) 75 | 76 | type instance Element (WrappedApplicative f a) = a 77 | instance Control.Applicative.Applicative f => MonoPointed (WrappedApplicative f a) 78 | instance Functor f => MonoFunctor (WrappedApplicative f a) 79 | 80 | type instance Element (MaybeApply f a) = a 81 | instance Functor f => MonoFunctor (MaybeApply f a) 82 | instance MonoPointed (MaybeApply f a) where 83 | opoint = MaybeApply . Right 84 | {-# INLINE opoint #-} 85 | 86 | type instance Element (TracedT m w a) = a 87 | instance (Comonad w, Data.Monoid.Monoid m) => MonoComonad (TracedT m w a) where 88 | oextract = extract 89 | oextend = extend 90 | instance Functor w => MonoFunctor (TracedT m w a) 91 | 92 | type instance Element (StoreT s w a) = a 93 | instance Comonad w => MonoComonad (StoreT s w a) where 94 | oextract = extract 95 | oextend = extend 96 | instance Functor w => MonoFunctor (StoreT s w a) 97 | 98 | type instance Element (EnvT e w a) = a 99 | instance Comonad w => MonoComonad (EnvT e w a) where 100 | oextract = extract 101 | oextend = extend 102 | instance Functor w => MonoFunctor (EnvT e w a) 103 | 104 | #if !MIN_VERSION_comonad(5,0,0) 105 | type instance Element (Coproduct f g a) = a 106 | instance (Functor f, Functor g) => MonoFunctor (Coproduct f g a) 107 | instance (Comonad f, Comonad g) => MonoComonad (Coproduct f g a) where 108 | oextract = extract 109 | oextend = extend 110 | #endif 111 | 112 | type instance Element (Static f a b) = b 113 | instance Applicative f => MonoPointed (Static f a b) 114 | instance Functor f => MonoFunctor (Static f a b) 115 | 116 | instance Comonad w => MonoComonad (IdentityT w a) where 117 | oextract = extract 118 | oextend = extend 119 | 120 | -- Comonad 121 | instance MonoComonad (Tree a) where 122 | oextract = extract 123 | oextend = extend 124 | instance MonoComonad (NonEmpty a) where 125 | oextract = extract 126 | oextend = extend 127 | instance MonoComonad (Identity a) where 128 | oextract = extract 129 | oextend = extend 130 | instance Monoid m => MonoComonad (m -> a) where 131 | oextract = extract 132 | oextend = extend 133 | instance MonoComonad (e, a) where 134 | oextract = extract 135 | oextend = extend 136 | instance MonoComonad (Arg a b) where 137 | oextract = extract 138 | oextend = extend 139 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable/Deque.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | module Data.Mutable.Deque 3 | ( Deque 4 | , UDeque 5 | , asUDeque 6 | , SDeque 7 | , asSDeque 8 | , BDeque 9 | , asBDeque 10 | , module Data.Mutable.Class 11 | ) where 12 | 13 | import Control.Exception (assert) 14 | import Control.Monad (liftM) 15 | import Data.Mutable.Class 16 | import qualified Data.Vector.Generic.Mutable as V 17 | import qualified Data.Vector.Mutable as B 18 | import qualified Data.Vector.Storable.Mutable as S 19 | import qualified Data.Vector.Unboxed.Mutable as U 20 | 21 | data DequeState v s a = DequeState 22 | (v s a) 23 | {-# UNPACK #-} !Int -- start 24 | {-# UNPACK #-} !Int -- size 25 | 26 | -- | A double-ended queue supporting any underlying vector type and any monad. 27 | -- 28 | -- This implements a circular double-ended queue with exponential growth. 29 | -- 30 | -- Since 0.2.0 31 | newtype Deque v s a = Deque (MutVar s (DequeState v s a)) 32 | 33 | -- | A 'Deque' specialized to unboxed vectors. 34 | -- 35 | -- Since 0.2.0 36 | type UDeque = Deque U.MVector 37 | 38 | -- | A 'Deque' specialized to storable vectors. 39 | -- 40 | -- Since 0.2.0 41 | type SDeque = Deque S.MVector 42 | 43 | -- | A 'Deque' specialized to boxed vectors. 44 | -- 45 | -- Since 0.2.0 46 | type BDeque = Deque B.MVector 47 | 48 | -- | 49 | -- Since 0.2.0 50 | asUDeque :: UDeque s a -> UDeque s a 51 | asUDeque = id 52 | 53 | -- | 54 | -- Since 0.2.0 55 | asSDeque :: SDeque s a -> SDeque s a 56 | asSDeque = id 57 | 58 | -- | 59 | -- Since 0.2.0 60 | asBDeque :: BDeque s a -> BDeque s a 61 | asBDeque = id 62 | 63 | instance MutableContainer (Deque v s a) where 64 | type MCState (Deque v s a) = s 65 | instance V.MVector v a => MutableCollection (Deque v s a) where 66 | type CollElement (Deque v s a) = a 67 | newColl = do 68 | v <- V.new baseSize 69 | liftM Deque $ newRef (DequeState v 0 0) 70 | where 71 | baseSize = 32 72 | {-# INLINE newColl #-} 73 | instance V.MVector v a => MutablePopFront (Deque v s a) where 74 | popFront (Deque var) = do 75 | DequeState v start size <- readRef var 76 | if size == 0 77 | then return Nothing 78 | else do 79 | x <- V.unsafeRead v start 80 | let start' = start + 1 81 | start'' 82 | | start' >= V.length v = 0 83 | | otherwise = start' 84 | writeRef var $! DequeState v start'' (size - 1) 85 | return $! Just x 86 | {-# INLINE popFront #-} 87 | instance V.MVector v a => MutablePopBack (Deque v s a) where 88 | popBack (Deque var) = do 89 | DequeState v start size <- readRef var 90 | if size == 0 91 | then return Nothing 92 | else do 93 | let size' = size - 1 94 | end = start + size' 95 | end' 96 | | end >= V.length v = end - V.length v 97 | | otherwise = end 98 | x <- V.unsafeRead v end' 99 | writeRef var $! DequeState v start size' 100 | return $! Just x 101 | {-# INLINE popBack #-} 102 | instance V.MVector v a => MutablePushFront (Deque v s a) where 103 | pushFront (Deque var) x = do 104 | DequeState v start size <- readRef var 105 | inner v start size 106 | where 107 | inner v start size = do 108 | if size >= V.length v 109 | then newVector v start size inner 110 | else do 111 | let size' = size + 1 112 | start' = (start - 1) `rem` V.length v 113 | start'' 114 | | start' < 0 = V.length v + start' 115 | | otherwise = start' 116 | V.unsafeWrite v start'' x 117 | writeRef var $! DequeState v start'' size' 118 | {-# INLINE pushFront #-} 119 | instance V.MVector v a => MutablePushBack (Deque v s a) where 120 | pushBack (Deque var) x = do 121 | DequeState v start size <- readRef var 122 | inner v start size 123 | where 124 | inner v start size = do 125 | if size >= V.length v 126 | then newVector v start size inner 127 | else do 128 | let end = start + size 129 | end' 130 | | end >= V.length v = end - V.length v 131 | | otherwise = end 132 | V.unsafeWrite v end' x 133 | writeRef var $! DequeState v start (size + 1) 134 | {-# INLINE pushBack #-} 135 | 136 | newVector :: (PrimMonad m, V.MVector v a) 137 | => v (PrimState m) a 138 | -> Int 139 | -> Int 140 | -> (v (PrimState m) a -> Int -> Int -> m b) 141 | -> m b 142 | newVector v size2 sizeOrig f = assert (sizeOrig == V.length v) $ do 143 | v' <- V.unsafeNew (V.length v * 2) 144 | let size1 = V.length v - size2 145 | V.unsafeCopy 146 | (V.unsafeTake size1 v') 147 | (V.unsafeSlice size2 size1 v) 148 | V.unsafeCopy 149 | (V.unsafeSlice size1 size2 v') 150 | (V.unsafeTake size2 v) 151 | f v' 0 sizeOrig 152 | {-# INLINE newVector #-} 153 | -------------------------------------------------------------------------------- /chunked-data/src/Data/ChunkedZip.hs: -------------------------------------------------------------------------------- 1 | -- | Various zipping and unzipping functions for chunked data structures. 2 | module Data.ChunkedZip where 3 | 4 | import Prelude hiding (zipWith, zipWith3) 5 | import Control.Arrow ((&&&), (***)) 6 | import qualified Data.List as List 7 | import qualified Data.List.NonEmpty as NonEmpty 8 | import Data.List.NonEmpty (NonEmpty) 9 | import qualified Data.Vector as Vector 10 | -- import qualified Data.Vector.Unboxed as UVector 11 | import qualified Data.Sequence as Seq 12 | import Control.Monad.Trans.Identity 13 | import Control.Monad.Trans.Reader 14 | import qualified Data.IntMap as IntMap 15 | import Data.Tree 16 | import Data.Functor.Compose 17 | import Data.Foldable (toList) 18 | 19 | class Functor f => Zip f where 20 | zipWith :: (a -> b -> c) -> f a -> f b -> f c 21 | 22 | zip :: f a -> f b -> f (a, b) 23 | zip = zipWith (,) 24 | 25 | zap :: f (a -> b) -> f a -> f b 26 | zap = zipWith id 27 | 28 | unzip :: f (a, b) -> (f a, f b) 29 | unzip = fmap fst &&& fmap snd 30 | 31 | instance Zip [] where 32 | zip = List.zip 33 | zipWith = List.zipWith 34 | unzip = List.unzip 35 | instance Zip NonEmpty where 36 | zipWith = NonEmpty.zipWith 37 | zip = NonEmpty.zip 38 | unzip = NonEmpty.unzip 39 | instance Zip Seq.Seq where 40 | zip = Seq.zip 41 | zipWith = Seq.zipWith 42 | unzip = (Seq.fromList *** Seq.fromList) . List.unzip . toList 43 | instance Zip Tree where 44 | zipWith f (Node a as) (Node b bs) = Node (f a b) (zipWith (zipWith f) as bs) 45 | instance Zip Vector.Vector where 46 | zip = Vector.zip 47 | unzip = Vector.unzip 48 | zipWith = Vector.zipWith 49 | {- 50 | instance Zip UVector where 51 | zip = UVector.zip 52 | unzip = UVector.unzip 53 | zipWith = UVector.zipWith 54 | -} 55 | 56 | instance Zip m => Zip (IdentityT m) where 57 | zipWith f (IdentityT m) (IdentityT n) = IdentityT (zipWith f m n) 58 | instance Zip ((->)a) where 59 | zipWith f g h a = f (g a) (h a) 60 | instance Zip m => Zip (ReaderT e m) where 61 | zipWith f (ReaderT m) (ReaderT n) = ReaderT $ \a -> 62 | zipWith f (m a) (n a) 63 | instance Zip IntMap.IntMap where 64 | zipWith = IntMap.intersectionWith 65 | instance (Zip f, Zip g) => Zip (Compose f g) where 66 | zipWith f (Compose a) (Compose b) = Compose $ zipWith (zipWith f) a b 67 | 68 | class Functor f => Zip3 f where 69 | zipWith3 :: (a -> b -> c -> d) -> f a -> f b -> f c -> f d 70 | 71 | zip3 :: f a -> f b -> f c -> f (a, b, c) 72 | zip3 = zipWith3 (\x y z -> (x,y,z)) 73 | 74 | zap3 :: f (a -> b -> c) -> f a -> f b -> f c 75 | zap3 = zipWith3 id 76 | 77 | unzip3 :: f (a, b, c) -> (f a, f b, f c) 78 | -- unzip3 = fmap (\(x,_,_)->x) &&& fmap (\(_,x,_)->x) &&& fmap (\(_,_,x)->x) 79 | 80 | instance Zip3 [] where 81 | zip3 = List.zip3 82 | unzip3 = List.unzip3 83 | zipWith3 = List.zipWith3 84 | instance Zip3 Vector.Vector where 85 | zip3 = Vector.zip3 86 | unzip3 = Vector.unzip3 87 | zipWith3 = Vector.zipWith3 88 | instance Zip3 Seq.Seq where 89 | zip3 = Seq.zip3 90 | unzip3 = (\(a, b, c) -> (Seq.fromList a, Seq.fromList b, Seq.fromList c)) . List.unzip3 . toList 91 | zipWith3 = Seq.zipWith3 92 | 93 | class Functor f => Zip4 f where 94 | zipWith4 :: (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e 95 | 96 | zip4 :: f a -> f b -> f c -> f d -> f (a, b, c, d) 97 | zip4 = zipWith4 (\w x y z -> (w, x,y,z)) 98 | 99 | zap4 :: f (a -> b -> c -> d) -> f a -> f b -> f c -> f d 100 | zap4 = zipWith4 id 101 | 102 | unzip4 :: f (a, b, c, d) -> (f a, f b, f c, f d) 103 | 104 | instance Zip4 [] where 105 | zip4 = List.zip4 106 | unzip4 = List.unzip4 107 | zipWith4 = List.zipWith4 108 | instance Zip4 Vector.Vector where 109 | zip4 = Vector.zip4 110 | unzip4 = Vector.unzip4 111 | zipWith4 = Vector.zipWith4 112 | instance Zip4 Seq.Seq where 113 | zip4 = Seq.zip4 114 | unzip4 = (\(a, b, c, d) -> (Seq.fromList a, Seq.fromList b, Seq.fromList c, Seq.fromList d)) . List.unzip4 . toList 115 | zipWith4 = Seq.zipWith4 116 | 117 | class Functor f => Zip5 f where 118 | zipWith5 :: (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g 119 | 120 | zip5 :: f a -> f b -> f c -> f d -> f e -> f (a, b, c, d, e) 121 | zip5 = zipWith5 (\v w x y z -> (v,w,x,y,z)) 122 | 123 | zap5 :: f (a -> b -> c -> d -> e) -> f a -> f b -> f c -> f d -> f e 124 | zap5 = zipWith5 id 125 | 126 | unzip5 :: f (a, b, c, d, e) -> (f a, f b, f c, f d, f e) 127 | 128 | instance Zip5 [] where 129 | zip5 = List.zip5 130 | unzip5 = List.unzip5 131 | zipWith5 = List.zipWith5 132 | instance Zip5 Vector.Vector where 133 | zip5 = Vector.zip5 134 | unzip5 = Vector.unzip5 135 | zipWith5 = Vector.zipWith5 136 | 137 | class Functor f => Zip6 f where 138 | zipWith6 :: (a -> b -> c -> d -> e -> g -> h) -> f a -> f b -> f c -> f d -> f e -> f g -> f h 139 | 140 | zip6 :: f a -> f b -> f c -> f d -> f e -> f g -> f (a, b, c, d, e, g) 141 | zip6 = zipWith6 (\u v w x y z -> (u, v,w,x,y,z)) 142 | 143 | zap6 :: f (a -> b -> c -> d -> e -> g) -> f a -> f b -> f c -> f d -> f e -> f g 144 | zap6 = zipWith6 id 145 | 146 | unzip6 :: f (a, b, c, d, e, g) -> (f a, f b, f c, f d, f e, f g) 147 | 148 | instance Zip6 [] where 149 | zip6 = List.zip6 150 | unzip6 = List.unzip6 151 | zipWith6 = List.zipWith6 152 | instance Zip6 Vector.Vector where 153 | zip6 = Vector.zip6 154 | unzip6 = Vector.unzip6 155 | zipWith6 = Vector.zipWith6 156 | 157 | class Functor f => Zip7 f where 158 | zipWith7 :: (a -> b -> c -> d -> e -> g -> h -> i) -> f a -> f b -> f c -> f d -> f e -> f g -> f h -> f i 159 | 160 | zip7 :: f a -> f b -> f c -> f d -> f e -> f g -> f h -> f (a, b, c, d, e, g, h) 161 | zip7 = zipWith7 (\t u v w x y z -> (t,u,v,w,x,y,z)) 162 | 163 | zap7 :: f (a -> b -> c -> d -> e -> g -> h) -> f a -> f b -> f c -> f d -> f e -> f g -> f h 164 | zap7 = zipWith7 id 165 | 166 | unzip7 :: f (a, b, c, d, e, g, h) -> (f a, f b, f c, f d, f e, f g, f h) 167 | -- unzip3 = fmap (\(x,_,_)->x) &&& fmap (\(_,x,_)->x) &&& fmap (\(_,_,x)->x) 168 | 169 | instance Zip7 [] where 170 | zip7 = List.zip7 171 | unzip7 = List.unzip7 172 | zipWith7 = List.zipWith7 173 | -------------------------------------------------------------------------------- /mono-traversable/src/Data/MonoTraversable/Unprefixed.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE FlexibleContexts #-} 3 | {-# LANGUAGE TypeFamilies #-} 4 | {-# LANGUAGE TypeOperators #-} 5 | -- | The functions in "Data.MonoTraversable" are all prefixed with the letter 6 | -- @o@ to avoid conflicts with their polymorphic counterparts. This module 7 | -- exports the same identifiers without the prefix, for all cases where the 8 | -- monomorphic variant loses no generality versus the polymorphic version. For 9 | -- example, 'olength' is just as general as @Data.Foldable.length@, so we 10 | -- export @length = length@. By contrast, 'omap' cannot fully subsume @fmap@ or 11 | -- @map@, so we do not provide such an export. 12 | -- 13 | -- @since 1.0.0 14 | module Data.MonoTraversable.Unprefixed where 15 | 16 | import Data.Int (Int64) 17 | import Data.MonoTraversable 18 | import Data.Monoid (Monoid) 19 | import Control.Applicative (Applicative) 20 | 21 | -- | Synonym for 'ofoldMap' 22 | -- 23 | -- @since 1.0.0 24 | foldMap :: (MonoFoldable mono, Data.Monoid.Monoid m) => (Element mono -> m) -> mono -> m 25 | foldMap = ofoldMap 26 | 27 | -- | Synonym for 'ofoldr' 28 | -- 29 | -- @since 1.0.0 30 | foldr :: MonoFoldable mono => (Element mono -> b -> b) -> b -> mono -> b 31 | foldr = ofoldr 32 | 33 | -- | Synonym for 'ofoldl'' 34 | -- 35 | -- @since 1.0.0 36 | foldl' :: MonoFoldable mono => (a -> Element mono -> a) -> a -> mono -> a 37 | foldl' = ofoldl' 38 | 39 | -- | Synonym for 'otoList' 40 | -- 41 | -- @since 1.0.0 42 | toList :: MonoFoldable mono => mono -> [Element mono] 43 | toList = otoList 44 | 45 | -- | Synonym for 'oall' 46 | -- 47 | -- @since 1.0.0 48 | all :: MonoFoldable mono => (Element mono -> Bool) -> mono -> Bool 49 | all = oall 50 | 51 | -- | Synonym for 'oany' 52 | -- 53 | -- @since 1.0.0 54 | any :: MonoFoldable mono => (Element mono -> Bool) -> mono -> Bool 55 | any = oany 56 | 57 | -- | Synonym for 'onull' 58 | -- 59 | -- @since 1.0.0 60 | null :: MonoFoldable mono => mono -> Bool 61 | null = onull 62 | 63 | -- | Synonym for 'olength' 64 | -- 65 | -- @since 1.0.0 66 | length :: MonoFoldable mono => mono -> Int 67 | length = olength 68 | 69 | -- | Synonym for 'olength64' 70 | -- 71 | -- @since 1.0.0 72 | length64 :: MonoFoldable mono => mono -> Int64 73 | length64 = olength64 74 | 75 | -- | Synonym for 'ocompareLength' 76 | -- 77 | -- @since 1.0.0 78 | compareLength :: (MonoFoldable mono, Integral i) => mono -> i -> Ordering 79 | compareLength = ocompareLength 80 | 81 | -- | Synonym for 'otraverse_' 82 | -- 83 | -- @since 1.0.0 84 | traverse_ :: (MonoFoldable mono, Control.Applicative.Applicative f) => (Element mono -> f b) -> mono -> f () 85 | traverse_ = otraverse_ 86 | 87 | -- | Synonym for 'ofor_' 88 | -- 89 | -- @since 1.0.0 90 | for_ :: (MonoFoldable mono, Applicative f) => mono -> (Element mono -> f b) -> f () 91 | for_ = ofor_ 92 | 93 | -- | Synonym for 'omapM_' 94 | -- 95 | -- @since 1.0.0 96 | mapM_ :: (MonoFoldable mono, Applicative m) 97 | => (Element mono -> m ()) -> mono -> m () 98 | mapM_ = omapM_ 99 | 100 | -- | Synonym for 'oforM_' 101 | -- 102 | -- @since 1.0.0 103 | forM_ :: (MonoFoldable mono, Applicative m) 104 | => mono -> (Element mono -> m ()) -> m () 105 | forM_ = oforM_ 106 | 107 | -- | Synonym for 'ofoldlM' 108 | -- 109 | -- @since 1.0.0 110 | foldlM :: (MonoFoldable mono, Monad m) 111 | => (a -> Element mono -> m a) 112 | -> a 113 | -> mono 114 | -> m a 115 | foldlM = ofoldlM 116 | 117 | -- | Synonym for 'ofoldMap1Ex' 118 | -- 119 | -- @since 1.0.0 120 | foldMap1Ex :: (MonoFoldable mono, Semigroup m) 121 | => (Element mono -> m) 122 | -> mono 123 | -> m 124 | foldMap1Ex = ofoldMap1Ex 125 | 126 | -- | Synonym for 'ofoldr1Ex' 127 | -- 128 | -- @since 1.0.0 129 | foldr1Ex :: MonoFoldable mono 130 | => (Element mono -> Element mono -> Element mono) 131 | -> mono 132 | -> Element mono 133 | foldr1Ex = ofoldr1Ex 134 | 135 | -- | Synonym for 'ofoldl1Ex'' 136 | -- 137 | -- @since 1.0.0 138 | foldl1Ex' :: MonoFoldable mono 139 | => (Element mono -> Element mono -> Element mono) 140 | -> mono 141 | -> Element mono 142 | foldl1Ex' = ofoldl1Ex' 143 | 144 | -- | Synonym for 'osum' 145 | -- 146 | -- @since 1.0.0 147 | sum :: (MonoFoldable mono, Num (Element mono)) => mono -> Element mono 148 | sum = osum 149 | 150 | -- | Synonym for 'oproduct' 151 | -- 152 | -- @since 1.0.0 153 | product :: (MonoFoldable mono, Num (Element mono)) => mono -> Element mono 154 | product = oproduct 155 | 156 | -- | Synonym for 'oand' 157 | -- 158 | -- @since 1.0.0 159 | and :: (MonoFoldable mono, Element mono ~ Bool) => mono -> Bool 160 | and = oand 161 | 162 | -- | Synonym for 'oor' 163 | -- 164 | -- @since 1.0.0 165 | or :: (MonoFoldable mono, Element mono ~ Bool) => mono -> Bool 166 | or = oor 167 | 168 | -- | Synonym for 'oconcatMap' 169 | -- 170 | -- @since 1.0.0 171 | concatMap :: (MonoFoldable mono, Monoid m) => (Element mono -> m) -> mono -> m 172 | concatMap = oconcatMap 173 | 174 | -- | Synonym for 'oelem' 175 | -- 176 | -- @since 1.0.0 177 | elem :: (MonoFoldable mono, Eq (Element mono)) => Element mono -> mono -> Bool 178 | elem = oelem 179 | 180 | -- | Synonym for 'onotElem' 181 | -- 182 | -- @since 1.0.0 183 | notElem :: (MonoFoldable mono, Eq (Element mono)) => Element mono -> mono -> Bool 184 | notElem = onotElem 185 | 186 | -- | Synonym for 'opoint' 187 | -- 188 | -- @since 1.0.0 189 | point :: MonoPointed mono => Element mono -> mono 190 | point = opoint 191 | 192 | -- | Synonym for 'ointercalate' 193 | -- 194 | -- @since 1.0.0 195 | intercalate :: (MonoFoldable mono, Monoid (Element mono)) 196 | => Element mono -> mono -> Element mono 197 | intercalate = ointercalate 198 | 199 | -- | Synonym for 'ofold' 200 | -- 201 | -- @since 1.0.0 202 | fold :: (MonoFoldable mono, Monoid (Element mono)) => mono -> Element mono 203 | fold = ofold 204 | 205 | -- | Synonym for 'oconcat' 206 | -- 207 | -- @since 1.0.0 208 | concat :: (MonoFoldable mono, Monoid (Element mono)) => mono -> Element mono 209 | concat = oconcat 210 | 211 | -- | Synonym for 'ofoldM' 212 | -- 213 | -- @since 1.0.0 214 | foldM :: (MonoFoldable mono, Monad m) => (a -> Element mono -> m a) -> a -> mono -> m a 215 | foldM = ofoldM 216 | 217 | -- | Synonym for 'osequence_' 218 | -- 219 | -- @since 1.0.0 220 | sequence_ :: (Applicative m, MonoFoldable mono, Element mono ~ (m ())) => mono -> m () 221 | sequence_ = osequence_ 222 | -------------------------------------------------------------------------------- /mutable-containers/test/Spec.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeFamilies #-} 2 | {-# LANGUAGE FlexibleContexts #-} 3 | {-# LANGUAGE TypeOperators #-} 4 | 5 | import Control.Monad (forM_) 6 | import Data.Mutable 7 | import Data.Sequence (Seq) 8 | import Data.Vector (Vector) 9 | import Test.Hspec 10 | import Test.Hspec.QuickCheck 11 | import Test.QuickCheck.Arbitrary 12 | import Test.QuickCheck.Gen 13 | 14 | main :: IO () 15 | main = hspec spec 16 | 17 | data RefAction 18 | = WriteRef Int 19 | | ModifyRef Int 20 | | ModifyRef' Int 21 | | AtomicModifyRef Int 22 | | AtomicModifyRef' Int 23 | deriving Show 24 | instance Arbitrary RefAction where 25 | arbitrary = oneof 26 | [ fmap WriteRef arbitrary 27 | , fmap ModifyRef arbitrary 28 | , fmap ModifyRef' arbitrary 29 | , fmap AtomicModifyRef arbitrary 30 | , fmap AtomicModifyRef' arbitrary 31 | ] 32 | 33 | data DequeAction 34 | = PushFront Int 35 | | PushBack Int 36 | | PopFront 37 | | PopBack 38 | deriving Show 39 | instance Arbitrary DequeAction where 40 | arbitrary = oneof $ concat 41 | [ replicate 25 $ fmap PushFront arbitrary 42 | , replicate 25 $ fmap PushBack arbitrary 43 | , [return PopFront, return PopBack] 44 | ] 45 | 46 | manyPushes :: [DequeAction] 47 | manyPushes = concat 48 | [ replicate 50 $ PushBack 0 49 | , replicate 50 PopFront 50 | , replicate 50 $ PushFront 0 51 | , replicate 50 PopBack 52 | ] 53 | 54 | specialCase :: [DequeAction] 55 | specialCase = 56 | [PushBack 9, PushBack 5,PushBack 11,PushBack 2,PushBack 13,PushBack 10,PushBack 4,PushBack 13,PushBack 7,PushBack 8,PushBack 6,PushBack 4,PushBack 7,PushBack 9,PushBack 10,PushBack 3,PushBack 2,PushBack 12,PushBack 12 ,PushBack 6,PushBack 3,PushBack 5,PushBack 14,PushBack 14,PushBack 11,PushBack 8,PopFront,PopFront,PopFront,PushBack 11,PushBack 3,PopFront,PopFront,PushBack 13,PushBack 12,PopFront,PushBack 10,PushBack 7,PopFront,PopFront,PushBack 13,PushBack 9,PopFront,PushBack 7,PushBack 2,PopFront,PopFront,PushBack 6,PushBack 4,PopFront,PopFront,PopFront,PushBack 9,PushBack 3,PopFront,PushBack 10,PushBack 6,PopFront,PopFront,PopFront,PushBack 12,PushBack 5,PopFront,PushBack 12,PushBack 5,PopFront,PushBack 6,PushBack 4,PopFront,PopFront,PopFront,PushBack 14,PushBack 10,PopFront,PushBack 14,PushBack 10,PopFront,PushBack 11,PushBack 8,PopFront,PushBack 8,PushBack 2,PopFront,PopFront,PopFront,PushBack 13,PushBack 7,PopFront,PushBack 12,PushBack 5,PopFront,PushBack 10,PushBack 8, PopFront,PushBack 7,PushBack 2,PopFront,PopFront,PushBack 9,PushBack 4,PopFront,PopFront,PopFront,PopFront,PopFront,PopFront,PopFront,PopFront,PushBack 4,PushBack 9,PushBack 3,PushBack 10,PushBack 6,PushBack 4,PushBack 13,PushBack 7,PushBack 9,PushBack 3,PopFront] 57 | 58 | spec :: Spec 59 | spec = do 60 | describe "Deque" $ do 61 | let runActions forceType actions = do 62 | base <- newColl :: IO (IORef [Int]) 63 | tested <- fmap forceType newColl 64 | forM_ (PopFront : PopBack : actions) $ \action -> do 65 | case action of 66 | PushFront i -> do 67 | pushFront base i 68 | pushFront tested i 69 | PushBack i -> do 70 | pushBack base i 71 | pushBack tested i 72 | PopFront -> do 73 | expected <- popFront base 74 | actual <- popFront tested 75 | actual `shouldBe` expected 76 | PopBack -> do 77 | expected <- popBack base 78 | actual <- popBack tested 79 | actual `shouldBe` expected 80 | let drain = do 81 | expected <- popBack base 82 | actual <- popBack tested 83 | actual `shouldBe` expected 84 | case actual of 85 | Just _ -> drain 86 | Nothing -> return $! () 87 | drain 88 | let test name forceType = describe name $ do 89 | prop "arbitrary actions" $ runActions forceType 90 | it "many pushes" $ runActions forceType manyPushes 91 | it "special case" $ runActions forceType specialCase 92 | 93 | test "UDeque" asUDeque 94 | test "SDeque" asSDeque 95 | test "BDeque" asBDeque 96 | test "DLList" asDLList 97 | test "MutVar Seq" (id :: MutVar (PrimState IO) (Seq Int) -> MutVar (PrimState IO) (Seq Int)) 98 | test "STRef Vector" (id :: STRef (PrimState IO) (Vector Int) -> STRef (PrimState IO) (Vector Int)) 99 | test "BRef Vector" (id :: BRef (PrimState IO) (Vector Int) -> BRef (PrimState IO) (Vector Int)) 100 | describe "Ref" $ do 101 | let test name forceType atomic atomic' = prop name $ \start actions -> do 102 | base <- fmap asIORef $ newRef start 103 | tested <- fmap forceType $ newRef start 104 | let check = do 105 | expected <- readRef base 106 | actual <- readRef tested 107 | expected `shouldBe` actual 108 | forM_ (actions :: [RefAction]) $ \action -> case action of 109 | WriteRef i -> do 110 | writeRef base i 111 | writeRef tested i 112 | check 113 | ModifyRef i -> do 114 | modifyRef base (+ i) 115 | modifyRef tested (+ i) 116 | check 117 | ModifyRef' i -> do 118 | modifyRef' base (subtract i) 119 | modifyRef' tested (subtract i) 120 | check 121 | AtomicModifyRef i -> do 122 | let f x = (x + i, ()) 123 | atomicModifyRef base f 124 | _ <- atomic tested f 125 | check 126 | AtomicModifyRef' i -> do 127 | atomicModifyRef' base $ \x -> (x - i, ()) 128 | _ <- atomic' tested $ \x -> (x - i, ()) 129 | check 130 | test "URef" asURef modifyRefHelper modifyRefHelper' 131 | test "PRef" asPRef modifyRefHelper modifyRefHelper' 132 | test "SRef" asSRef modifyRefHelper modifyRefHelper' 133 | test "BRef" asBRef modifyRefHelper modifyRefHelper' 134 | test "STRef" asSTRef modifyRefHelper modifyRefHelper' 135 | test "MutVar" asMutVar atomicModifyRef atomicModifyRef' 136 | 137 | modifyRefHelper :: (MCState c ~ PrimState IO, RefElement c ~ Int, MutableRef c) 138 | => c 139 | -> (Int -> (Int, ())) 140 | -> IO () 141 | modifyRefHelper ref f = modifyRef ref $ \i -> 142 | let (x, y) = f i 143 | in y `seq` x 144 | 145 | modifyRefHelper' :: (MCState c ~ PrimState IO, RefElement c ~ Int, MutableRef c) 146 | => c 147 | -> (Int -> (Int, ())) 148 | -> IO () 149 | modifyRefHelper' ref f = modifyRef' ref $ \i -> 150 | let (x, y) = f i 151 | in y `seq` x 152 | -------------------------------------------------------------------------------- /mono-traversable/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # ChangeLog for mono-traversable 2 | 3 | ## 1.0.21.0 4 | 5 | * Support for vector 0.13.2.0, adding instances for [`Data.Vector.Strict`](https://hackage.haskell.org/package/vector-0.13.2.0/docs/Data-Vector-Strict.html) data structure. 6 | [#244](https://github.com/snoyberg/mono-traversable/issues/244) 7 | 8 | ## 1.0.20.0 9 | 10 | * Added instances for [`Reverse`](https://hackage.haskell.org/package/transformers-0.6.1.1/docs/Data-Functor-Reverse.html#t:Reverse) data structure. 11 | 12 | ## 1.0.19.1 13 | 14 | * Removed 'highly experimental' warning haddock comment from Data.Containers. 15 | 16 | ## 1.0.19.0 17 | 18 | * Added `filterWithKey` to `IsMap`. 19 | [#232](https://github.com/snoyberg/mono-traversable/pull/232) 20 | 21 | ## 1.0.18.0 22 | 23 | * Added MonoPointed instance for text Builder 24 | [#225](https://github.com/snoyberg/mono-traversable/pull/225) 25 | 26 | ## 1.0.17.0 27 | 28 | * Added `inits`, `tails`, `initTails` to class `IsSequence` with tests and benchmarks for `initTails`. 29 | * Improved ghc benchmark flags. 30 | * Removed extraneous constraint `IsSequence` from `initMay`. 31 | 32 | ## 1.0.16.0 33 | 34 | * Added MonoPointed instance for bytestring Builder 35 | [#219](https://github.com/snoyberg/mono-traversable/pull/219#pullrequestreview-1879553961) 36 | 37 | ## 1.0.15.3 38 | 39 | * Compile with GHC 9.2 (`Option` removed from `base-4.16`) 40 | [#199](https://github.com/snoyberg/mono-traversable/issues/199) 41 | 42 | ## 1.0.15.2 43 | 44 | * Support transformers 0.6.0.0 [#196](https://github.com/snoyberg/mono-traversable/issues/196) 45 | * Compile with GHC 9 [#193](https://github.com/snoyberg/mono-traversable/pull/193) 46 | 47 | ## 1.0.15.1 48 | 49 | * Remove whitespace after `@` in as-patterns for GHC HEAD [#186](https://github.com/snoyberg/mono-traversable/pull/186) 50 | 51 | ## 1.0.15.0 52 | 53 | * Added `toNonEmpty` to `Data.NonNull` 54 | [#185](https://github.com/snoyberg/mono-traversable/pull/185) 55 | 56 | ## 1.0.14.0 57 | * Added `WrappedMono` to `Data.MonoTraversable` 58 | [#182](https://github.com/snoyberg/mono-traversable/pull/182) 59 | 60 | ## 1.0.13.0 61 | * Added `WrappedPoly` to `Data.MonoTraversable` 62 | [#180](https://github.com/snoyberg/mono-traversable/pull/180) 63 | 64 | ## 1.0.12.0 65 | * Added `filterSet` to `Data.Containers` 66 | * Use container specific implementations for `filterSet` and `filterMap` 67 | [#178](https://github.com/snoyberg/mono-traversable/pull/178) 68 | 69 | ## 1.0.11.0 70 | 71 | * Adding monomorphic instances for GHC.Generics and Data.Proxy types 72 | [#175](https://github.com/snoyberg/mono-traversable/issues/175) 73 | 74 | ## 1.0.10.0 75 | 76 | * Make index work on negative indices 77 | [#172](https://github.com/snoyberg/mono-traversable/issues/172) 78 | [#114](https://github.com/snoyberg/mono-traversable/issues/114) 79 | 80 | ## 1.0.9.0 81 | 82 | * Added `filterMap` to `Data.Containers` 83 | [#167](https://github.com/snoyberg/mono-traversable/pull/167) 84 | 85 | ## 1.0.8.1 86 | 87 | * Compat with gauge 0.1 and 0.2 88 | 89 | ## 1.0.8.0 90 | 91 | * Switch to gauge 92 | * Relax constraint on `singleton` to `MonoPointed` 93 | [#156](https://github.com/snoyberg/mono-traversable/issues/156) 94 | 95 | ## 1.0.7.0 96 | 97 | * Add `dropPrefix` and `dropSuffix` to `Data.Sequences` [#139](https://github.com/snoyberg/mono-traversable/issues/139) 98 | * Change `sort` implementation [#153](https://github.com/snoyberg/mono-traversable/issues/153) 99 | 100 | ## 1.0.6.0 101 | 102 | * Add `mapNonNull` function to `Data.NonNull` [#150](https://github.com/snoyberg/mono-traversable/issues/150) 103 | 104 | ## 1.0.5.0 105 | 106 | * Move `oelem` and `onotElem` into the `MonoFoldable` class [#133](https://github.com/snoyberg/mono-traversable/issues/133) 107 | * Change `instance MonoFoldable (Set e)` to `instance Ord e => MonoFoldable (Set e)` 108 | 109 | ## 1.0.4.0 110 | 111 | * Add `dropEnd` function to the `IsSequence` class, and a specialized implementation for `Text` 112 | 113 | ## 1.0.3.0 114 | 115 | * Add `ensurePrefix` and `ensureSuffix` functions [#141](https://github.com/snoyberg/mono-traversable/pull/141) 116 | 117 | ## 1.0.2.1 118 | 119 | * Fix test suite for foldl 1.3 120 | 121 | ## 1.0.2 122 | 123 | * `IsSequence` class: add `lengthIndex` [#127](https://github.com/snoyberg/mono-traversable/pull/127) 124 | 125 | ## 1.0.1.3 126 | 127 | * Make 'olength' for Set and Map O(1) [#125](https://github.com/snoyberg/mono-traversable/pull/125) 128 | 129 | ## 1.0.1.2 130 | 131 | * Support for GHC 8.2 132 | 133 | ## 1.0.1.1 134 | 135 | * Fix typo in rewrite rule 136 | 137 | ## 1.0.1 138 | 139 | * Add `replaceElem` and `replaceSeq` [#107](https://github.com/snoyberg/mono-traversable/pull/107) 140 | 141 | ## 1.0.0.1 142 | 143 | * Add missing export [#101](https://github.com/snoyberg/mono-traversable/pull/101) 144 | 145 | ## 1.0.0 146 | 147 | * Implement the cleanups described in [#95](https://github.com/snoyberg/mono-traversable/issues/95) 148 | * Split out `Data.MinLen` to `minlen` package, and have `Data.NonNull` stand on its own 149 | * Remove `Data.ByteVector` 150 | * Split out extra typeclass instances to `mono-traversable-instances` 151 | * Remove the `Eq` and `Ord` specific classes, and instead use rewrite rules 152 | * Provide the `Data.MonoTraversable.Unprefixed` module 153 | * Generalize `unwords` and `unlines` [#87](https://github.com/snoyberg/mono-traversable/pull/87) 154 | * Add `tailMay` and `initMay` [#89](https://github.com/snoyberg/mono-traversable/issues/89) 155 | 156 | ## 0.10.2 157 | 158 | * Add `delete` and `deleteBy` methods to EqSequence [#94](https://github.com/snoyberg/mono-traversable/pull/94) 159 | 160 | ## 0.10.1.1 161 | 162 | * Remove unneeded INLINEs [#90](https://github.com/snoyberg/mono-traversable/issues/90) 163 | 164 | ## 0.10.1 165 | 166 | * Allow comonad-5 [#86](https://github.com/snoyberg/mono-traversable/issues/86) 167 | 168 | ## 0.10.0.1 169 | 170 | * Instance for Data.Sequence.Seq is incorrect. [#83](https://github.com/snoyberg/mono-traversable/issues/83) 171 | 172 | ## 0.10.0 173 | 174 | * Remove `Functor` instance for `MinLen` [#82](https://github.com/snoyberg/mono-traversable/issues/82) 175 | 176 | ## 0.9.3 177 | 178 | * Added `intercalate`, `splitWhen`, `splitElem`, and `splitSeq` [#80](https://github.com/snoyberg/mono-traversable/pull/80) 179 | 180 | ## 0.9.2.1 181 | 182 | * Tweak test suite for 32-bit systems [#78](https://github.com/snoyberg/mono-traversable/issues/78) 183 | 184 | ## 0.9.2 185 | 186 | * MonoComonad 187 | 188 | ## 0.9.1 189 | 190 | * Fill in missing Mono\* instances [#72](https://github.com/snoyberg/mono-traversable/pull/72) 191 | 192 | ## 0.9.0.1 193 | 194 | * Documentation improvements 195 | 196 | ## 0.9.0 197 | 198 | * Better fixity for mlcons [#56](https://github.com/snoyberg/mono-traversable/issues/56) 199 | 200 | ## 0.8.0.1 201 | 202 | README updates 203 | 204 | ## 0.8.0 205 | 206 | A new MonoFoldableEq class that takes `elem` and `notElem` from `EqSequence`. 207 | `EqSequence` now inherits from `MonoFoldableEq`. 208 | 209 | For most users that do not define instances this should not be a breaking change. 210 | However, any instance of `EqSequence` now needs to define `MonoFoldableEq`. 211 | 212 | 213 | ## 0.7.0 214 | 215 | * Work on better polymorphic containers 216 | * Rename `mapKeysWith` to `omapKeysWith` 217 | * Add new class `BiPolyMap` 218 | * Add `keys` to `IsSet` 219 | * New class `HasKeysSet` 220 | * Added `index`, `indexEx` and `unsafeIndex`. 221 | * Added `sortOn` 222 | -------------------------------------------------------------------------------- /mutable-containers/README.md: -------------------------------------------------------------------------------- 1 | [![Coverage Status](https://img.shields.io/coveralls/fpco/mutable-containers.svg)](https://coveralls.io/r/fpco/mutable-containers) 2 | ![Travis Build Status](https://travis-ci.org/fpco/mutable-containers.svg) 3 | 4 | One of Haskell's strengths is immutable data structures. These structures make 5 | it easier to reason about code, simplify concurrency and parallelism, and in 6 | some cases can improve performance by allowing sharing. However, there are still 7 | classes of problems where mutable data structures can both be more convenient, 8 | and provide a performance boost. This library is meant to provide such 9 | structures in a performant, well tested way. It also provides a simple 10 | abstraction over such data structures via typeclasses. 11 | 12 | Before anything else, let me provide the caveats of this package: 13 | 14 | * Don't use this package unless you have a good reason to! Immutable data structures are a better approach most of the time! 15 | * This code is intentionally *not* multithread safe. If you need something like a concurrent queue, there are many options on Hackage, from `Chan` to `TChan`, to [chaselev-deque](http://hackage.haskell.org/package/chaselev-deque). 16 | 17 | We'll first talk about the general approach to APIs in this package. Next, 18 | there are two main sets of abstractions provided, which we'll cover in the 19 | following two sections, along with their concrete implementations. Finally, 20 | we'll cover benchmarks. 21 | 22 | ## API structure 23 | 24 | The API takes heavy advantage of the `PrimMonad` typeclass from the primitive 25 | package. This allows our data structures to work in both `IO` and `ST` code. 26 | Each data structure has an associated type, `MCState`, which gives the 27 | primitive state for that structure. For example, in the case of `IORef`, that 28 | state is `RealWorld`, whereas for `STRef s`, it would be `s`. This associated 29 | type is quite similar to the `PrimState` associated type from primitive, and in 30 | many type signatures you'll see an equality constraint along the lines of: 31 | 32 | ```haskell 33 | PrimState m ~ MCState c 34 | ``` 35 | 36 | For those who are wondering, `MCState` stands for "mutable container state." 37 | 38 | All actions are part of a typeclass, which allows for generic access to 39 | different types of structures quite easily. In addition, we provide type hint 40 | functions, such as `asIORef`, which can help specify types when using such 41 | generic functions. For example, a common idiom might be: 42 | 43 | ```haskell 44 | ioref <- fmap asIORef $ newRef someVal 45 | ``` 46 | 47 | Wherever possible, we stick to well accepted naming and type signature 48 | standards. For example, note how closely `modifyRef` and `modifyRef'` match 49 | `modifyIORef` and `modifyIORef'`. 50 | 51 | ## Single cell references 52 | 53 | The base package provides both `IORef` and `STRef` as boxed mutable references, 54 | for storing a single value. The primitive package also provides `MutVar`, which 55 | generalizes over both of those and works for any `PrimMonad` instance. The 56 | `MutableRef` typeclass in this package abstracts over all three of those. It 57 | has two associated types: `MCState` for the primitive state, and `RefElement` 58 | to specify what is contained by the reference. 59 | 60 | You may be wondering: why not just take the reference as a type parameter? That 61 | wouldn't allow us to have monomorphic reference types, which may be useful 62 | under some circumstances. This is a similar motivation to how the 63 | `mono-traversable` package works. 64 | 65 | In addition to providing an abstraction over `IORef`, `STRef`, and `MutVar`, 66 | this package provides four additional single-cell mutable references. `URef`, 67 | `SRef`, and `BRef` all contain a 1-length mutable vector under the surface, 68 | which is unboxed, storable, and boxed, respectively. The advantage of the first 69 | two over boxed standard boxed references is that it can avoid a significant 70 | amount of allocation overhead. See [the relevant Stack Overflow 71 | discussion](http://stackoverflow.com/questions/27261813/why-is-my-little-stref-int-require-allocating-gigabytes) 72 | and the benchmarks below. 73 | 74 | While `BRef` doesn't give this same advantage (since the values are still 75 | boxed), it was trivial to include it along with the other two, and does 76 | actually demonstrate a performance advantage. Unlike `URef` and `SRef`, there 77 | is no restriction on the type of value it can store. 78 | 79 | The final reference type is `PRef`. Unlike the other three mentioned, it 80 | doesn't use vectors at all, but instead drops down directly to a mutable 81 | bytearray to store values. This means it has slightly less overhead (no need to 82 | store the size of the vector), but also restricts the types of things that can 83 | be stored (only instances of `Prim`). 84 | 85 | You should benchmark your program to determine the most efficient reference 86 | type, but generally speaking `PRef` will be most performant, followed by `URef` 87 | and `SRef`, and finally `BRef`. 88 | 89 | ## Collections 90 | 91 | Collections allow you to push and pop values to the beginning and end of 92 | themselves. Since different data structures allow different operations, each 93 | operation goes into its own typeclass, appropriately named `MutablePushFront`, 94 | `MutablePushBack`, `MutablePopFront`, and `MutablePopBack`. There is also a 95 | parent typeclass `MutableCollection` which provides: 96 | 97 | 1. The `CollElement` associated type to indicate what kinds of values are in the collection. 98 | 2. The `newColl` function to create a new, empty collection. 99 | 100 | The `mono-traversable` package provides a typeclass `IsSequence` which 101 | abstracts over sequence-like things. In particular, it provides operations for 102 | `cons`, `snoc`, `uncons`, and `unsnoc`. Using this abstraction, we can provide 103 | an instance for all of the typeclasses listed above for any mutable reference 104 | containing an instance of `IsSequence`, e.g. `IORef [Int]` or `BRef s (Seq 105 | Double)`. 106 | 107 | Note that the performance of some of these combinations is *terrible*. In 108 | particular, `pushBack` or `popBack` on a list requires traversing the entire 109 | list, and any push operations on a `Vector` requires copying the entire 110 | contents of the vector. Caveat emptor! If you *must* use one of these 111 | structures, it's highly recommended to use `Seq`, which gives the best overall 112 | performance. 113 | 114 | However, in addition to these instances, this package also provides two 115 | additional data structures: double-ended queues and doubly-linked lists. The 116 | former is based around mutable vectors, and therefore as unboxed (`UDeque`), 117 | storable (`SDeque`), and boxed (`BDeque`) variants. Doubly-linked lists have no 118 | such variety, and are simply `DLList`s. 119 | 120 | For general purpose queue-like structures, `UDeque` or `SDeque` is likely to 121 | give you best performance. As usual, benchmark your own program to be certain, 122 | and see the benchmark results below. 123 | 124 | ## Benchmark results 125 | 126 | The following benchmarks were performed on January 7, 2015, against version 0.2.0. 127 | 128 | ### Ref benchmark 129 | 130 | ``` 131 | benchmarking IORef 132 | time 4.322 μs (4.322 μs .. 4.323 μs) 133 | 1.000 R² (1.000 R² .. 1.000 R²) 134 | mean 4.322 μs (4.322 μs .. 4.323 μs) 135 | std dev 1.401 ns (1.114 ns .. 1.802 ns) 136 | 137 | benchmarking STRef 138 | time 4.484 μs (4.484 μs .. 4.485 μs) 139 | 1.000 R² (1.000 R² .. 1.000 R²) 140 | mean 4.484 μs (4.484 μs .. 4.484 μs) 141 | std dev 941.0 ps (748.5 ps .. 1.164 ns) 142 | 143 | benchmarking MutVar 144 | time 4.482 μs (4.482 μs .. 4.483 μs) 145 | 1.000 R² (1.000 R² .. 1.000 R²) 146 | mean 4.482 μs (4.482 μs .. 4.483 μs) 147 | std dev 843.2 ps (707.9 ps .. 1.003 ns) 148 | 149 | benchmarking URef 150 | time 2.020 μs (2.019 μs .. 2.020 μs) 151 | 1.000 R² (1.000 R² .. 1.000 R²) 152 | mean 2.020 μs (2.019 μs .. 2.020 μs) 153 | std dev 955.2 ps (592.2 ps .. 1.421 ns) 154 | 155 | benchmarking PRef 156 | time 2.015 μs (2.014 μs .. 2.015 μs) 157 | 1.000 R² (1.000 R² .. 1.000 R²) 158 | mean 2.014 μs (2.014 μs .. 2.015 μs) 159 | std dev 901.3 ps (562.8 ps .. 1.238 ns) 160 | 161 | benchmarking SRef 162 | time 2.231 μs (2.230 μs .. 2.232 μs) 163 | 1.000 R² (1.000 R² .. 1.000 R²) 164 | mean 2.231 μs (2.230 μs .. 2.231 μs) 165 | std dev 1.938 ns (1.589 ns .. 2.395 ns) 166 | 167 | benchmarking BRef 168 | time 4.279 μs (4.279 μs .. 4.279 μs) 169 | 1.000 R² (1.000 R² .. 1.000 R²) 170 | mean 4.279 μs (4.279 μs .. 4.279 μs) 171 | std dev 1.281 ns (1.016 ns .. 1.653 ns) 172 | ``` 173 | 174 | ### Deque benchmark 175 | 176 | ``` 177 | benchmarking IORef [Int] 178 | time 8.371 ms (8.362 ms .. 8.382 ms) 179 | 1.000 R² (1.000 R² .. 1.000 R²) 180 | mean 8.386 ms (8.378 ms .. 8.398 ms) 181 | std dev 29.25 μs (20.73 μs .. 42.47 μs) 182 | 183 | benchmarking IORef (Seq Int) 184 | time 142.9 μs (142.7 μs .. 143.1 μs) 185 | 1.000 R² (1.000 R² .. 1.000 R²) 186 | mean 142.7 μs (142.6 μs .. 142.9 μs) 187 | std dev 542.8 ns (426.5 ns .. 697.0 ns) 188 | 189 | benchmarking UDeque 190 | time 107.5 μs (107.4 μs .. 107.6 μs) 191 | 1.000 R² (1.000 R² .. 1.000 R²) 192 | mean 107.5 μs (107.4 μs .. 107.6 μs) 193 | std dev 227.4 ns (171.8 ns .. 297.8 ns) 194 | 195 | benchmarking SDeque 196 | time 97.82 μs (97.76 μs .. 97.89 μs) 197 | 1.000 R² (1.000 R² .. 1.000 R²) 198 | mean 97.82 μs (97.78 μs .. 97.89 μs) 199 | std dev 169.5 ns (110.6 ns .. 274.5 ns) 200 | 201 | benchmarking BDeque 202 | time 113.5 μs (113.4 μs .. 113.6 μs) 203 | 1.000 R² (1.000 R² .. 1.000 R²) 204 | mean 113.6 μs (113.5 μs .. 113.7 μs) 205 | std dev 300.4 ns (221.8 ns .. 424.1 ns) 206 | 207 | benchmarking DList 208 | time 156.5 μs (156.3 μs .. 156.6 μs) 209 | 1.000 R² (1.000 R² .. 1.000 R²) 210 | mean 156.4 μs (156.3 μs .. 156.6 μs) 211 | std dev 389.5 ns (318.3 ns .. 502.8 ns) 212 | ``` 213 | 214 | ## Test coverage 215 | 216 | As of version 0.2.0, this package has 100% test coverage. If you look at the 217 | report yourself, you'll see some uncovered code; it's just the automatically 218 | derived `Show` instance needed for QuickCheck inside the test suite itself. 219 | -------------------------------------------------------------------------------- /mutable-containers/src/Data/Mutable/Class.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ConstraintKinds #-} 2 | {-# LANGUAGE FlexibleContexts #-} 3 | {-# LANGUAGE FlexibleInstances #-} 4 | {-# LANGUAGE TypeFamilies #-} 5 | {-# LANGUAGE TypeOperators #-} 6 | -- | Various typeclasses for mutable containers. 7 | module Data.Mutable.Class 8 | ( PrimMonad 9 | , PrimState 10 | , RealWorld 11 | , MutableQueue 12 | , MutableStack 13 | , MutableDeque 14 | , IORef 15 | , asIORef 16 | , STRef 17 | , asSTRef 18 | , MutVar 19 | , asMutVar 20 | , MutableContainer (..) 21 | , MutableRef (..) 22 | , MutableAtomicRef (..) 23 | , MutableCollection (..) 24 | , MutablePushFront (..) 25 | , MutablePushBack (..) 26 | , MutablePopFront (..) 27 | , MutablePopBack (..) 28 | , pushFrontRef 29 | , pushBackRef 30 | , popFrontRef 31 | , popBackRef 32 | ) where 33 | 34 | import Control.Monad.Primitive 35 | import Data.IORef 36 | import Data.Monoid 37 | import Data.MonoTraversable (Element) 38 | import Data.Primitive.MutVar 39 | import qualified Data.Sequences as Seqs 40 | import Data.STRef 41 | 42 | -- | The parent typeclass for all mutable containers. 43 | -- 44 | -- Since 0.2.0 45 | class MutableContainer c where 46 | -- | Associated type giving the primitive state token for the given 47 | -- container, much like 'PrimState' from primitive. 48 | -- 49 | -- Since 0.2.0 50 | type MCState c 51 | 52 | instance MutableContainer (IORef a) where 53 | type MCState (IORef a) = PrimState IO 54 | instance MutableContainer (STRef s a) where 55 | type MCState (STRef s a) = s 56 | instance MutableContainer (MutVar s a) where 57 | type MCState (MutVar s a) = s 58 | 59 | -- | Typeclass for single-cell mutable references. 60 | -- 61 | -- Since 0.2.0 62 | class MutableContainer c => MutableRef c where 63 | -- | Associated type giving the type of the value inside the mutable 64 | -- reference. 65 | -- 66 | -- Since 0.2.0 67 | type RefElement c 68 | 69 | -- | Create a new mutable reference with the given value. 70 | -- 71 | -- Since 0.2.0 72 | newRef :: (PrimMonad m, PrimState m ~ MCState c) 73 | => RefElement c 74 | -> m c 75 | 76 | -- | Read the current value in the mutable reference. 77 | -- 78 | -- Since 0.2.0 79 | readRef :: (PrimMonad m, PrimState m ~ MCState c) 80 | => c 81 | -> m (RefElement c) 82 | 83 | -- | Write a new value to the mutable reference. 84 | -- 85 | -- Since 0.2.0 86 | writeRef :: (PrimMonad m, PrimState m ~ MCState c) 87 | => c 88 | -> RefElement c 89 | -> m () 90 | 91 | -- | Modify the value in the mutable reference, without necessarily forcing the result. 92 | -- 93 | -- Note: some implementations /will/ force the result, in particular 94 | -- @PRef@, @SRef@, and @URef@. 95 | -- 96 | -- Since 0.2.0 97 | modifyRef :: (PrimMonad m, PrimState m ~ MCState c) 98 | => c 99 | -> (RefElement c -> RefElement c) 100 | -> m () 101 | 102 | -- | Modify the value in the mutable reference, forcing the result. 103 | -- 104 | -- Since 0.2.0 105 | modifyRef' :: (PrimMonad m, PrimState m ~ MCState c) 106 | => c 107 | -> (RefElement c -> RefElement c) 108 | -> m () 109 | 110 | instance MutableRef (IORef a) where 111 | type RefElement (IORef a) = a 112 | newRef = primToPrim . newIORef 113 | {-# INLINE newRef #-} 114 | readRef = primToPrim . readIORef 115 | {-# INLINE readRef #-} 116 | writeRef c = primToPrim . writeIORef c 117 | {-# INLINE writeRef #-} 118 | modifyRef c = primToPrim . modifyIORef c 119 | {-# INLINE modifyRef #-} 120 | modifyRef' c = primToPrim . modifyIORef' c 121 | {-# INLINE modifyRef' #-} 122 | instance MutableRef (STRef s a) where 123 | type RefElement (STRef s a) = a 124 | newRef = primToPrim . newSTRef 125 | {-# INLINE newRef #-} 126 | readRef = primToPrim . readSTRef 127 | {-# INLINE readRef #-} 128 | writeRef c = primToPrim . writeSTRef c 129 | {-# INLINE writeRef #-} 130 | modifyRef c = primToPrim . modifySTRef c 131 | {-# INLINE modifyRef #-} 132 | modifyRef' c = primToPrim . modifySTRef' c 133 | {-# INLINE modifyRef' #-} 134 | instance MutableRef (MutVar s a) where 135 | type RefElement (MutVar s a) = a 136 | newRef = newMutVar 137 | {-# INLINE newRef #-} 138 | readRef = readMutVar 139 | {-# INLINE readRef #-} 140 | writeRef = writeMutVar 141 | {-# INLINE writeRef #-} 142 | modifyRef = modifyMutVar 143 | {-# INLINE modifyRef #-} 144 | modifyRef' = modifyMutVar' 145 | {-# INLINE modifyRef' #-} 146 | 147 | -- | @MutableRef@s that provide for atomic modifications of their contents. 148 | -- 149 | -- Since 0.2.0 150 | class MutableRef c => MutableAtomicRef c where 151 | -- | Modify the value without necessarily forcing the result. 152 | -- 153 | -- Since 0.2.0 154 | atomicModifyRef 155 | :: (PrimMonad m, PrimState m ~ MCState c) 156 | => c 157 | -> (RefElement c -> (RefElement c, a)) 158 | -> m a 159 | 160 | -- | Modify the value, forcing the result. 161 | -- 162 | -- Since 0.2.0 163 | atomicModifyRef' 164 | :: (PrimMonad m, PrimState m ~ MCState c) 165 | => c 166 | -> (RefElement c -> (RefElement c, a)) 167 | -> m a 168 | instance MutableAtomicRef (IORef a) where 169 | atomicModifyRef c = primToPrim . atomicModifyIORef c 170 | {-# INLINE atomicModifyRef #-} 171 | atomicModifyRef' c = primToPrim . atomicModifyIORef' c 172 | {-# INLINE atomicModifyRef' #-} 173 | instance MutableAtomicRef (MutVar s a) where 174 | atomicModifyRef = atomicModifyMutVar 175 | {-# INLINE atomicModifyRef #-} 176 | atomicModifyRef' = atomicModifyMutVar' 177 | {-# INLINE atomicModifyRef' #-} 178 | 179 | -- | Containers which contain 0 or more values. 180 | -- 181 | -- Since 0.2.0 182 | class MutableContainer c => MutableCollection c where 183 | -- | The type of each value in the collection. 184 | -- 185 | -- Since 0.2.0 186 | type CollElement c 187 | 188 | -- | Create a new, empty collection. 189 | -- 190 | -- Since 0.2.0 191 | newColl :: (PrimMonad m, PrimState m ~ MCState c) 192 | => m c 193 | instance Data.Monoid.Monoid w => MutableCollection (IORef w) where 194 | type CollElement (IORef w) = Element w 195 | newColl = newRef mempty 196 | {-# INLINE newColl #-} 197 | instance Monoid w => MutableCollection (STRef s w) where 198 | type CollElement (STRef s w) = Element w 199 | newColl = newRef mempty 200 | {-# INLINE newColl #-} 201 | instance Monoid w => MutableCollection (MutVar s w) where 202 | type CollElement (MutVar s w) = Element w 203 | newColl = newRef mempty 204 | {-# INLINE newColl #-} 205 | 206 | -- | Take a value from the front of the collection, if available. 207 | -- 208 | -- Since 0.2.0 209 | class MutableCollection c => MutablePopFront c where 210 | -- | Take a value from the front of the collection, if available. 211 | -- 212 | -- Since 0.2.0 213 | popFront :: (PrimMonad m, PrimState m ~ MCState c) 214 | => c 215 | -> m (Maybe (CollElement c)) 216 | popFrontRef 217 | :: ( PrimMonad m 218 | , PrimState m ~ MCState c 219 | , MutableRef c 220 | , CollElement c ~ Element (RefElement c) 221 | , Seqs.IsSequence (RefElement c) 222 | ) 223 | => c 224 | -> m (Maybe (CollElement c)) 225 | popFrontRef c = do 226 | l <- readRef c 227 | case Seqs.uncons l of 228 | Nothing -> return Nothing 229 | Just (x, xs) -> do 230 | writeRef c xs 231 | return (Just x) 232 | {-# INLINE popFrontRef #-} 233 | instance Seqs.IsSequence a => MutablePopFront (IORef a) where 234 | popFront = popFrontRef 235 | {-# INLINE popFront #-} 236 | instance Seqs.IsSequence a => MutablePopFront (STRef s a) where 237 | popFront = popFrontRef 238 | {-# INLINE popFront #-} 239 | instance Seqs.IsSequence a => MutablePopFront (MutVar s a) where 240 | popFront = popFrontRef 241 | {-# INLINE popFront #-} 242 | 243 | -- | Place a value at the front of the collection. 244 | -- 245 | -- Since 0.2.0 246 | class MutableCollection c => MutablePushFront c where 247 | -- | Place a value at the front of the collection. 248 | -- 249 | -- Since 0.2.0 250 | pushFront :: (PrimMonad m, PrimState m ~ MCState c) 251 | => c 252 | -> CollElement c 253 | -> m () 254 | pushFrontRef 255 | :: ( PrimMonad m 256 | , PrimState m ~ MCState c 257 | , MutableRef c 258 | , CollElement c ~ Element (RefElement c) 259 | , Seqs.IsSequence (RefElement c) 260 | ) 261 | => c 262 | -> CollElement c 263 | -> m () 264 | pushFrontRef c e = modifyRef' c (Seqs.cons e) 265 | {-# INLINE pushFrontRef #-} 266 | instance Seqs.IsSequence a => MutablePushFront (IORef a) where 267 | pushFront = pushFrontRef 268 | {-# INLINE pushFront #-} 269 | instance Seqs.IsSequence a => MutablePushFront (STRef s a) where 270 | pushFront = pushFrontRef 271 | {-# INLINE pushFront #-} 272 | instance Seqs.IsSequence a => MutablePushFront (MutVar s a) where 273 | pushFront = pushFrontRef 274 | {-# INLINE pushFront #-} 275 | 276 | -- | Take a value from the back of the collection, if available. 277 | -- 278 | -- Since 0.2.0 279 | class MutableCollection c => MutablePopBack c where 280 | -- | Take a value from the back of the collection, if available. 281 | -- 282 | -- Since 0.2.0 283 | popBack :: (PrimMonad m, PrimState m ~ MCState c) 284 | => c 285 | -> m (Maybe (CollElement c)) 286 | popBackRef 287 | :: ( PrimMonad m 288 | , PrimState m ~ MCState c 289 | , MutableRef c 290 | , CollElement c ~ Element (RefElement c) 291 | , Seqs.IsSequence (RefElement c) 292 | ) 293 | => c 294 | -> m (Maybe (CollElement c)) 295 | popBackRef c = do 296 | l <- readRef c 297 | case Seqs.unsnoc l of 298 | Nothing -> return Nothing 299 | Just (xs, x) -> do 300 | writeRef c xs 301 | return (Just x) 302 | {-# INLINE popBackRef #-} 303 | instance Seqs.IsSequence a => MutablePopBack (IORef a) where 304 | popBack = popBackRef 305 | {-# INLINE popBack #-} 306 | instance Seqs.IsSequence a => MutablePopBack (STRef s a) where 307 | popBack = popBackRef 308 | {-# INLINE popBack #-} 309 | instance Seqs.IsSequence a => MutablePopBack (MutVar s a) where 310 | popBack = popBackRef 311 | {-# INLINE popBack #-} 312 | 313 | -- | Place a value at the back of the collection. 314 | -- 315 | -- Since 0.2.0 316 | class MutableCollection c => MutablePushBack c where 317 | -- | Place a value at the back of the collection. 318 | -- 319 | -- Since 0.2.0 320 | pushBack :: (PrimMonad m, PrimState m ~ MCState c) 321 | => c 322 | -> CollElement c 323 | -> m () 324 | pushBackRef 325 | :: ( PrimMonad m 326 | , PrimState m ~ MCState c 327 | , MutableRef c 328 | , CollElement c ~ Element (RefElement c) 329 | , Seqs.IsSequence (RefElement c) 330 | ) 331 | => c 332 | -> CollElement c 333 | -> m () 334 | pushBackRef c e = modifyRef' c (`Seqs.snoc` e) 335 | {-# INLINE pushBackRef #-} 336 | instance Seqs.IsSequence a => MutablePushBack (IORef a) where 337 | pushBack = pushBackRef 338 | {-# INLINE pushBack #-} 339 | instance Seqs.IsSequence a => MutablePushBack (STRef s a) where 340 | pushBack = pushBackRef 341 | {-# INLINE pushBack #-} 342 | instance Seqs.IsSequence a => MutablePushBack (MutVar s a) where 343 | pushBack = pushBackRef 344 | {-# INLINE pushBack #-} 345 | 346 | -- | Collections which allow pushing and popping at the front (aka FIFOs). 347 | -- 348 | -- Since 0.2.0 349 | type MutableQueue c = (MutablePopFront c, MutablePushBack c) 350 | 351 | -- | Collections which allow pushing at the back and popping at the front (aka FILOs). 352 | -- 353 | -- Since 0.2.0 354 | type MutableStack c = (MutablePopFront c, MutablePushFront c) 355 | 356 | -- | Collections which allow pushing and popping at the front and back. 357 | -- 358 | -- Since 0.2.0 359 | type MutableDeque c = (MutableQueue c, MutablePushFront c, MutablePopBack c) 360 | 361 | -- | 362 | -- Since 0.2.0 363 | asIORef :: IORef a -> IORef a 364 | asIORef = id 365 | 366 | -- | 367 | -- Since 0.2.0 368 | asSTRef :: STRef s a -> STRef s a 369 | asSTRef = id 370 | 371 | -- | 372 | -- Since 0.2.0 373 | asMutVar :: MutVar s a -> MutVar s a 374 | asMutVar = id 375 | -------------------------------------------------------------------------------- /mono-traversable/src/Data/NonNull.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE TypeFamilies #-} 3 | {-# LANGUAGE FlexibleContexts, FlexibleInstances #-} 4 | {-# LANGUAGE DefaultSignatures #-} 5 | {-# LANGUAGE DeriveDataTypeable #-} 6 | {-# LANGUAGE StandaloneDeriving #-} 7 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 8 | -- | "Data.NonNull" extends the concepts from 9 | -- "Data.List.NonEmpty" to any 'MonoFoldable'. 10 | -- 11 | -- 'NonNull' is a newtype wrapper for a container with 1 or more elements. 12 | module Data.NonNull ( 13 | NonNull 14 | , fromNullable 15 | , impureNonNull 16 | , nonNull 17 | , toNullable 18 | , fromNonEmpty 19 | , toNonEmpty 20 | , ncons 21 | , nuncons 22 | , splitFirst 23 | , nfilter 24 | , nfilterM 25 | , nReplicate 26 | , head 27 | , tail 28 | , last 29 | , init 30 | , ofoldMap1 31 | , ofold1 32 | , ofoldr1 33 | , ofoldl1' 34 | , maximum 35 | , maximumBy 36 | , minimum 37 | , minimumBy 38 | , (<|) 39 | , toMinList 40 | , mapNonNull 41 | , GrowingAppend 42 | ) where 43 | 44 | import Prelude hiding (head, tail, init, last, reverse, seq, filter, replicate, maximum, minimum) 45 | import Control.Arrow (second) 46 | import Control.Exception.Base (Exception, throw) 47 | import Data.Data 48 | import qualified Data.List.NonEmpty as NE 49 | import Data.Maybe (fromMaybe) 50 | import Data.MonoTraversable 51 | import Data.Sequences 52 | import Control.Monad.Trans.State.Strict (evalState, state) 53 | 54 | data NullError = NullError String deriving (Show, Typeable) 55 | instance Exception NullError 56 | 57 | -- | A monomorphic container that is not null. 58 | newtype NonNull mono = NonNull 59 | { toNullable :: mono 60 | -- ^ __Safely__ convert from a non-null monomorphic container to a nullable monomorphic container. 61 | } 62 | deriving (Eq, Ord, Read, Show, Data, Typeable) 63 | type instance Element (NonNull mono) = Element mono 64 | deriving instance MonoFunctor mono => MonoFunctor (NonNull mono) 65 | deriving instance MonoFoldable mono => MonoFoldable (NonNull mono) 66 | instance MonoTraversable mono => MonoTraversable (NonNull mono) where 67 | otraverse f (NonNull x) = fmap NonNull (otraverse f x) 68 | {-# INLINE otraverse #-} 69 | 70 | instance GrowingAppend mono => GrowingAppend (NonNull mono) 71 | 72 | instance (Semigroup mono, GrowingAppend mono) => Semigroup (NonNull mono) where 73 | NonNull x <> NonNull y = NonNull (x <> y) 74 | 75 | instance SemiSequence seq => SemiSequence (NonNull seq) where 76 | type Index (NonNull seq) = Index seq 77 | 78 | intersperse e = unsafeMap $ intersperse e 79 | reverse = unsafeMap reverse 80 | find f = find f . toNullable 81 | cons x = unsafeMap $ cons x 82 | snoc xs x = unsafeMap (flip snoc x) xs 83 | sortBy f = unsafeMap $ sortBy f 84 | 85 | -- | This function is unsafe, and must not be exposed from this module. 86 | unsafeMap :: (mono -> mono) -> NonNull mono -> NonNull mono 87 | unsafeMap f (NonNull x) = NonNull (f x) 88 | 89 | instance MonoPointed mono => MonoPointed (NonNull mono) where 90 | opoint = NonNull . opoint 91 | {-# INLINE opoint #-} 92 | instance IsSequence mono => MonoComonad (NonNull mono) where 93 | oextract = head 94 | oextend f (NonNull mono) = NonNull 95 | . flip evalState mono 96 | . ofor mono 97 | . const 98 | . state 99 | $ \mono' -> (f (NonNull mono'), tailEx mono') 100 | 101 | -- | __Safely__ convert from an __unsafe__ monomorphic container to a __safe__ 102 | -- non-null monomorphic container. 103 | fromNullable :: MonoFoldable mono => mono -> Maybe (NonNull mono) 104 | fromNullable mono 105 | | onull mono = Nothing 106 | | otherwise = Just (NonNull mono) 107 | 108 | -- | __Unsafely__ convert from an __unsafe__ monomorphic container to a __safe__ 109 | -- non-null monomorphic container. 110 | -- 111 | -- Throws an exception if the monomorphic container is empty. 112 | -- 113 | -- @since 1.0.0 114 | impureNonNull :: MonoFoldable mono => mono -> NonNull mono 115 | impureNonNull nullable = 116 | fromMaybe (throw $ NullError "Data.NonNull.impureNonNull (NonNull default): expected non-null") 117 | $ fromNullable nullable 118 | 119 | -- | Old synonym for 'impureNonNull' 120 | nonNull :: MonoFoldable mono => mono -> NonNull mono 121 | nonNull = impureNonNull 122 | {-# DEPRECATED nonNull "Please use the more explicit impureNonNull instead" #-} 123 | 124 | -- | __Safely__ convert from a 'NonEmpty' list to a non-null monomorphic container. 125 | fromNonEmpty :: IsSequence seq => NE.NonEmpty (Element seq) -> NonNull seq 126 | fromNonEmpty = impureNonNull . fromList . NE.toList 127 | {-# INLINE fromNonEmpty #-} 128 | 129 | -- | __Safely__ convert from a 'NonNull' container to a 'NonEmpty' list. 130 | -- 131 | -- @since 1.0.15.0 132 | toNonEmpty :: MonoFoldable mono => NonNull mono -> NE.NonEmpty (Element mono) 133 | toNonEmpty = NE.fromList . otoList 134 | 135 | -- | Specializes 'fromNonEmpty' to lists only. 136 | toMinList :: NE.NonEmpty a -> NonNull [a] 137 | toMinList = fromNonEmpty 138 | 139 | -- | Prepend an element to a 'SemiSequence', creating a non-null 'SemiSequence'. 140 | -- 141 | -- Generally this uses cons underneath. 142 | -- cons is not efficient for most data structures. 143 | -- 144 | -- Alternatives: 145 | -- 146 | -- * if you don't need to cons, use 'fromNullable' or 'nonNull' if you can create your structure in one go. 147 | -- * if you need to cons, you might be able to start off with an efficient data structure such as a 'NonEmpty' List. 148 | -- 'fromNonEmpty' will convert that to your data structure using the structure's fromList function. 149 | ncons :: SemiSequence seq => Element seq -> seq -> NonNull seq 150 | ncons x xs = nonNull $ cons x xs 151 | 152 | -- | Extract the first element of a sequence and the rest of the non-null sequence if it exists. 153 | nuncons :: IsSequence seq => NonNull seq -> (Element seq, Maybe (NonNull seq)) 154 | nuncons xs = 155 | second fromNullable 156 | $ fromMaybe (error "Data.NonNull.nuncons: data structure is null, it should be non-null") 157 | $ uncons (toNullable xs) 158 | 159 | -- | Same as 'nuncons' with no guarantee that the rest of the sequence is non-null. 160 | splitFirst :: IsSequence seq => NonNull seq -> (Element seq, seq) 161 | splitFirst xs = 162 | fromMaybe (error "Data.NonNull.splitFirst: data structure is null, it should be non-null") 163 | $ uncons (toNullable xs) 164 | 165 | -- | Equivalent to @"Data.Sequences".'Data.Sequences.filter'@, 166 | -- but works on non-nullable sequences. 167 | nfilter :: IsSequence seq => (Element seq -> Bool) -> NonNull seq -> seq 168 | nfilter f = filter f . toNullable 169 | 170 | -- | Equivalent to @"Data.Sequences".'Data.Sequences.filterM'@, 171 | -- but works on non-nullable sequences. 172 | nfilterM :: (Monad m, IsSequence seq) => (Element seq -> m Bool) -> NonNull seq -> m seq 173 | nfilterM f = filterM f . toNullable 174 | 175 | -- | Equivalent to @"Data.Sequences".'Data.Sequences.replicate'@ 176 | -- 177 | -- @i@ must be @> 0@ 178 | -- 179 | -- @i <= 0@ is treated the same as providing @1@ 180 | nReplicate :: IsSequence seq => Index seq -> Element seq -> NonNull seq 181 | nReplicate i = nonNull . replicate (max 1 i) 182 | 183 | -- | __Safe__ version of 'tailEx', only working on non-nullable sequences. 184 | tail :: IsSequence seq => NonNull seq -> seq 185 | tail = tailEx . toNullable 186 | {-# INLINE tail #-} 187 | 188 | -- | __Safe__ version of 'initEx', only working on non-nullable sequences. 189 | init :: IsSequence seq => NonNull seq -> seq 190 | init = initEx . toNullable 191 | {-# INLINE init #-} 192 | 193 | infixr 5 <| 194 | 195 | -- | Prepend an element to a non-null 'SemiSequence'. 196 | (<|) :: SemiSequence seq => Element seq -> NonNull seq -> NonNull seq 197 | x <| y = ncons x (toNullable y) 198 | 199 | -- | Return the first element of a monomorphic container. 200 | -- 201 | -- Safe version of 'headEx', only works on monomorphic containers wrapped in a 202 | -- 'NonNull'. 203 | head :: MonoFoldable mono => NonNull mono -> Element mono 204 | head = headEx . toNullable 205 | {-# INLINE head #-} 206 | 207 | -- | Return the last element of a monomorphic container. 208 | -- 209 | -- Safe version of 'lastEx', only works on monomorphic containers wrapped in a 210 | -- 'NonNull'. 211 | last :: MonoFoldable mono => NonNull mono -> Element mono 212 | last = lastEx . toNullable 213 | {-# INLINE last #-} 214 | 215 | -- | Map each element of a monomorphic container to a semigroup, and combine the 216 | -- results. 217 | -- 218 | -- Safe version of 'ofoldMap1Ex', only works on monomorphic containers wrapped in a 219 | -- 'NonNull'. 220 | -- 221 | -- ==== __Examples__ 222 | -- 223 | -- @ 224 | -- > let xs = ncons ("hello", 1 :: 'Integer') [(" world", 2)] 225 | -- > 'ofoldMap1' 'fst' xs 226 | -- "hello world" 227 | -- @ 228 | ofoldMap1 :: (MonoFoldable mono, Semigroup m) => (Element mono -> m) -> NonNull mono -> m 229 | ofoldMap1 f = ofoldMap1Ex f . toNullable 230 | {-# INLINE ofoldMap1 #-} 231 | 232 | -- | Join a monomorphic container, whose elements are 'Semigroup's, together. 233 | -- 234 | -- Safe, only works on monomorphic containers wrapped in a 'NonNull'. 235 | -- 236 | -- ==== __Examples__ 237 | -- 238 | -- @ 239 | -- > let xs = ncons "a" ["b", "c"] 240 | -- > xs 241 | -- 'NonNull' {toNullable = ["a","b","c"]} 242 | -- 243 | -- > 'ofold1' xs 244 | -- "abc" 245 | -- @ 246 | ofold1 :: (MonoFoldable mono, Semigroup (Element mono)) => NonNull mono -> Element mono 247 | ofold1 = ofoldMap1 id 248 | {-# INLINE ofold1 #-} 249 | 250 | -- | Right-associative fold of a monomorphic container with no base element. 251 | -- 252 | -- Safe version of 'ofoldr1Ex', only works on monomorphic containers wrapped in a 253 | -- 'NonNull'. 254 | -- 255 | -- @'foldr1' f = "Prelude".'Prelude.foldr1' f . 'otoList'@ 256 | -- 257 | -- ==== __Examples__ 258 | -- 259 | -- @ 260 | -- > let xs = ncons "a" ["b", "c"] 261 | -- > 'ofoldr1' (++) xs 262 | -- "abc" 263 | -- @ 264 | ofoldr1 :: MonoFoldable mono 265 | => (Element mono -> Element mono -> Element mono) 266 | -> NonNull mono 267 | -> Element mono 268 | ofoldr1 f = ofoldr1Ex f . toNullable 269 | {-# INLINE ofoldr1 #-} 270 | 271 | -- | Strict left-associative fold of a monomorphic container with no base 272 | -- element. 273 | -- 274 | -- Safe version of 'ofoldl1Ex'', only works on monomorphic containers wrapped in a 275 | -- 'NonNull'. 276 | -- 277 | -- @'foldl1'' f = "Prelude".'Prelude.foldl1'' f . 'otoList'@ 278 | -- 279 | -- ==== __Examples__ 280 | -- 281 | -- @ 282 | -- > let xs = ncons "a" ["b", "c"] 283 | -- > 'ofoldl1'' (++) xs 284 | -- "abc" 285 | -- @ 286 | ofoldl1' :: MonoFoldable mono 287 | => (Element mono -> Element mono -> Element mono) 288 | -> NonNull mono 289 | -> Element mono 290 | ofoldl1' f = ofoldl1Ex' f . toNullable 291 | {-# INLINE ofoldl1' #-} 292 | 293 | -- | Get the maximum element of a monomorphic container. 294 | -- 295 | -- Safe version of 'maximumEx', only works on monomorphic containers wrapped in a 296 | -- 'NonNull'. 297 | -- 298 | -- ==== __Examples__ 299 | -- 300 | -- @ 301 | -- > let xs = ncons 1 [2, 3 :: Int] 302 | -- > 'maximum' xs 303 | -- 3 304 | -- @ 305 | maximum :: (MonoFoldable mono, Ord (Element mono)) 306 | => NonNull mono 307 | -> Element mono 308 | maximum = maximumEx . toNullable 309 | {-# INLINE maximum #-} 310 | 311 | -- | Get the minimum element of a monomorphic container. 312 | -- 313 | -- Safe version of 'minimumEx', only works on monomorphic containers wrapped in a 314 | -- 'NonNull'. 315 | -- 316 | -- ==== __Examples__ 317 | -- 318 | -- @ 319 | -- > let xs = ncons 1 [2, 3 :: Int] 320 | -- > 'minimum' xs 321 | -- 1 322 | -- @ 323 | minimum :: (MonoFoldable mono, Ord (Element mono)) 324 | => NonNull mono 325 | -> Element mono 326 | minimum = minimumEx . toNullable 327 | {-# INLINE minimum #-} 328 | 329 | -- | Get the maximum element of a monomorphic container, 330 | -- using a supplied element ordering function. 331 | -- 332 | -- Safe version of 'maximumByEx', only works on monomorphic containers wrapped in a 333 | -- 'NonNull'. 334 | maximumBy :: MonoFoldable mono 335 | => (Element mono -> Element mono -> Ordering) 336 | -> NonNull mono 337 | -> Element mono 338 | maximumBy cmp = maximumByEx cmp . toNullable 339 | {-# INLINE maximumBy #-} 340 | 341 | -- | Get the minimum element of a monomorphic container, 342 | -- using a supplied element ordering function. 343 | -- 344 | -- Safe version of 'minimumByEx', only works on monomorphic containers wrapped in a 345 | -- 'NonNull'. 346 | minimumBy :: MonoFoldable mono 347 | => (Element mono -> Element mono -> Ordering) 348 | -> NonNull mono 349 | -> Element mono 350 | minimumBy cmp = minimumByEx cmp . toNullable 351 | {-# INLINE minimumBy #-} 352 | 353 | -- | 'fmap' over the underlying container in a 'NonNull'. 354 | -- 355 | -- @since 1.0.6.0 356 | 357 | -- ==== __Examples__ 358 | -- 359 | -- @ 360 | -- > let xs = 'ncons' 1 [2, 3 :: Int] 361 | -- > 'mapNonNull' 'show' xs 362 | -- 'NonNull' {toNullable = [\"1\",\"2\",\"3\"]} 363 | -- @ 364 | mapNonNull :: (Functor f, MonoFoldable (f b)) 365 | => (a -> b) 366 | -> NonNull (f a) 367 | -> NonNull (f b) 368 | mapNonNull f = impureNonNull . fmap f . toNullable 369 | -------------------------------------------------------------------------------- /mono-traversable/README.md: -------------------------------------------------------------------------------- 1 | mono-traversable 2 | ================ 3 | 4 | Type classes for mapping, folding, and traversing monomorphic and polymorphic containers. 5 | Haskell is good at operating over polymorphic containers such as a list `[a]`. 6 | A monomorphic container is one such as Text which has a type `Text` that does not expose a type variable for the underlying characters. 7 | 8 | mono-traversable also adds 9 | 10 | * `IsSequence`, etc for operating over sequential data types 11 | * `IsSet`, `IsMap`, etc for unifying set and map APIs 12 | * `NonNull` for making partial functions (head, tail) total 13 | 14 | In addition to this package, the 15 | [mono-traversable-instances](https://www.stackage.org/package/mono-traversable-instances) 16 | package provides a number of orphan instances. 17 | 18 | 19 | Using Typeclasses 20 | ----------------- 21 | 22 | There are 2 use cases for mono-traversable: application authors and library authors. 23 | 24 | ### Library authors 25 | 26 | As a library author, if you want to allow a user to pass in a `Text` or a `String`, 27 | then you need to expose an API with a mono-traversable typeclass. 28 | You should think twice about using mono-traversable though because 29 | 30 | * Using Typeclasses makes type inference more difficult. It is usually better to force the user to give a `Text`. Another option is to just have multiple APIs. 31 | * If you are operating on polymorphic structures in which the normal typeclasses suffice, you should just use them from base. On the other hand, even if you are using polymorphic containers you may want to leverage `IsSequence` or `MinLen`. 32 | 33 | ### Application authors 34 | 35 | As an application author, you should consider using classy-prelude, which leans heavily on mono-traversable. 36 | 37 | When writing your own function signatures, you should default to making them concrete: if you are actually using a list, then make your function take a list rather than an `IsSequence`. This will improve type inference, error messages, and make your code easier to understand. When you decide to use a `Vector` instead of a list, change the type signature to use a `Vector`. When you actually need a function to both accept a `Vector` and a list, it is easy to change the function signature to the more abstract typeclasses that you require. 38 | 39 | 40 | Standard Typeclasses 41 | -------------------- 42 | 43 | in the upcoming GHC 7.10, using `Functor`, `Foldable`, and `Traversable` will become common-place. This means that rather than using `List.map`, `Vector.map`, etc, the map from the prelude will work on all data types that are a Functor. Of course, you can already do this now using `fmap`. 44 | 45 | For a Haskeller, it is important to understand `Functor`, `Applicative`, `Monad`, `Foldable`, and `Monoid`: these are encountered in every day code. For mono-traversable, it is most important to understand [Foldable](https://www.haskell.org/haskellwiki/Typeclassopedia#Foldable). 46 | 47 | mono-traversable Typeclasses 48 | ---------------------------- 49 | 50 | ### MonoFunctor 51 | 52 | Same as Functor, but cannot change the type. 53 | 54 | ``` haskell 55 | type family Element mono 56 | type instance Element Text = Char 57 | type instance Element [a] = a 58 | ``` 59 | 60 | Element is a type family. This tells the compiler to substitute `Char` for `Element Text`. 61 | We can create this rule for every monomorphic container we want to operate on such as `Text` 62 | And we can also create it for a polymorphic container. 63 | 64 | Now lets compare MonoFunctor to the normal Functor. 65 | 66 | ``` haskell 67 | fmap :: Functor f => (a -> b) -> f a -> f b 68 | omap :: MonoFunctor mono => (Element mono -> Element mono) -> mono -> mono 69 | ``` 70 | 71 | So there is no type-change from `a` to `b`, the contained type must stay the same (`Element mono -> Element mono`). 72 | 73 | Here is the MonoFunctor typeclass definition 74 | 75 | ``` haskell 76 | class MonoFunctor mono where 77 | omap :: (Element mono -> Element mono) -> mono -> mono 78 | default omap :: (Functor f, Element (f a) ~ a, f a ~ mono) => (a -> a) -> f a -> f a 79 | omap = fmap 80 | ``` 81 | 82 | And we can write some instances 83 | 84 | ``` haskell 85 | instance MonoFunctor T.Text where 86 | omap = T.map 87 | 88 | instance MonoFunctor [a] 89 | ``` 90 | 91 | The list definition was able to default to using `fmap` so no body was needed. 92 | 93 | 94 | ### MonoFoldable 95 | 96 | Same as Foldable, but also operates over monomorphic containers. 97 | 98 | MonoFoldable is the heart of the power of mono-traversable (and arguably the package should be named mono-foldable) because anything that can be done with `Foldable` can be done with `MonoFoldable`. 99 | The reason why is that a monomorphic container can never change its type. 100 | So `omap` is a restricted `fmap`. 101 | However, folding generates a *new* structure, so we have no such concerns. 102 | In the classy-prelude package, map is set to `fmap` and omap must be used separately. 103 | However, foldMap is set to just use the mono-traversable version: `ofoldMap` 104 | 105 | ``` haskell 106 | class Foldable t where 107 | foldMap :: Monoid m => (a -> m) -> t a -> m 108 | foldr :: (a -> b -> b) -> b -> t a -> b 109 | ... 110 | 111 | class MonoFoldable mono where 112 | ofoldMap :: Monoid m => (Element mono -> m) -> mono -> m 113 | ofoldr :: (Element mono -> b -> b) -> b -> mono -> b 114 | ... 115 | ``` 116 | 117 | There are additional Typeclasses which build on MonoFoldable 118 | 119 | ``` haskell 120 | class (MonoFoldable mono, Monoid mono) => MonoFoldableMonoid mono where 121 | oconcatMap :: (Element mono -> mono) -> mono -> mono 122 | 123 | class (MonoFoldable mono, Ord (Element mono)) => MonoFoldableOrd mono where 124 | maximumEx :: mono -> Element mono 125 | minimumEx :: mono -> Element mono 126 | 127 | class MonoPointed mono where 128 | opoint :: Element mono -> mono 129 | ``` 130 | 131 | MonoPointed abstracts over the concept of a singleton. For any `Applicative`, `opoint` is the same as `pure` from Applicative. Since mono-traversable did not bother with a `MonoApplicative` typeclass, we added `MonoPointed` to still have the functionality of `pure`. 132 | 133 | 134 | ### MonoTraversable 135 | 136 | `MonoTraversable` is `Traversable` for monomorphic containers, just as 137 | `MonoFunctor` is `Functor` for monomorphic containers. 138 | 139 | ``` haskell 140 | class (Functor t, Foldable t) => Traversable t where 141 | traverse :: Applicative f => (a -> f b) -> t a -> f (t b) 142 | ... 143 | 144 | class (MonoFunctor mono, MonoFoldable mono) => MonoTraversable mono where 145 | otraverse :: Applicative f => (Element mono -> f (Element mono)) -> mono -> f mono 146 | ... 147 | ``` 148 | 149 | 150 | ### Containers 151 | 152 | * SetContainer: unifies operations across `Set` and `Map` 153 | * PolyMap: differenceMap and intersectionMap 154 | * IsSet: unifies operations across different `Set`s 155 | * IsMap: unifies operations across different `Map`s 156 | * MonoZip: zip operations on MonoFunctors. 157 | 158 | Note that because `Set` is not a Functor (and therefore neither a MonoFunctor nor MonoTraversable), one must use `setFromList` and `setToList` to `omap` or `otraverse` over the elements of a `Set`. 159 | 160 | 161 | ### Sequences 162 | 163 | `IsSequence` contains list-like operations. 164 | 165 | ``` haskell 166 | -- | Sequence Laws: 167 | -- 168 | -- > fromList . otoList = id 169 | -- > fromList (x <> y) = fromList x <> fromList y 170 | -- > otoList (fromList x <> fromList y) = x <> y 171 | class (Monoid seq, MonoTraversable seq, SemiSequence seq, MonoPointed seq) => IsSequence seq where 172 | fromList :: [Element seq] -> seq 173 | break :: (Element seq -> Bool) -> seq -> (seq, seq) 174 | ... 175 | ``` 176 | 177 | The laws state that an IsSequence is a list-like (sequential) structure. 178 | 179 | * an `IsSequence` is not just something that can be converted to a list (`MonoFoldable`), but something that can be created from a list. 180 | * Converting to and from a list does not change the `IsSequence`, and it doesn't even change the `IsSequence` if you do the conversions on chunks of the `IsSequence`. 181 | 182 | SemiSequence is required by IsSequence. It is conceptually the same as IsSequence, but contains operations that can also be used on a `NonEmpty` or a `MinLen` (which are SemiGroups) because they do not reduce the number of elements in the sequence. 183 | 184 | 185 | There are some more typeclasess that build on top of IsSequence. 186 | 187 | ``` haskell 188 | class (IsSequence seq, Eq (Element seq)) => EqSequence seq where 189 | class (EqSequence seq, MonoFoldableOrd seq) => OrdSequence seq where 190 | class (IsSequence t, IsString t, Element t ~ Char) => Textual t where 191 | words :: t -> [t] 192 | unwords :: [t] -> t 193 | lines :: t -> [t] 194 | unlines :: [t] -> t 195 | toLower :: t -> t 196 | toUpper :: t -> t 197 | ... 198 | ``` 199 | 200 | Textual functions are always safe to use with Unicode (it is possible to misuse other functions that operate on individual characters). 201 | 202 | 203 | ### MinLen 204 | 205 | Did you notice minimumEx and maximumEx from above? Ex stands for 'Exception'. 206 | An exception will occur if you call minimumEx on an empty list. 207 | MinLen is a tool to guarantee that this never occurs, and instead to prove that there are one or more elements in your list. 208 | 209 | ``` haskell 210 | minimumEx :: MonoFoldable mono => mono -> Element mono 211 | 212 | -- | like Data.List, but not partial on a MonoFoldable 213 | minimum :: MonoFoldableOrd mono => MinLen (Succ nat) mono -> Element mono 214 | minimum = minimumEx . unMinLen 215 | 216 | newtype MinLen nat mono = MinLen { unMinLen :: mono } 217 | deriving (Eq, Ord, Read, Show, Data, Typeable, Functor) 218 | 219 | -- Type level naturals 220 | data Zero = Zero 221 | data Succ nat = Succ nat 222 | ``` 223 | 224 | The `minimum` function exposed from `MinLen` is very similar to `minimumEx`, but has a `MinLen` wrapper that ensures it will never throw an exception. 225 | `MinLen` is a newtype with a phantom type that contains information about the minimum number of elements we know are in the structure. That is done through type-level Peano numbers. 226 | 227 | What do we know about the input to minimum? If nat is Zero, then it reduces to `MinLen (Succ Zero) mono`. Succ means successor, and the successor of 0 is 1, so the data structure has a minimum length of 1. 228 | 229 | Lets see this in practice 230 | 231 | ``` haskell 232 | > minimum [] 233 | :3:9: 234 | Couldn't match expected type ‘MinLen (Succ nat0) mono’ 235 | with actual type ‘[t0]’ 236 | 237 | 238 | > minimum [1,2,3] 239 | -- same error as above 240 | 241 | > minimum (toMinList (3 :| [2,1])) 242 | 1 243 | > minimum (3 `mlcons` toMinLenZero [2,1]) 244 | 1 245 | ``` 246 | 247 | Here we used Data.List.NonEmpty combined with toMinList or we just work with a List and prove through the usage of cons that it has more than one element. 248 | 249 | 250 | 251 | Adding instances 252 | ---------------- 253 | 254 | If you have a _polymorphic_ data type which is a member of one of the relevant typeclasses ([Functor](http://hackage.haskell.org/package/base/docs/Data-Functor.html), 255 | [Foldable](http://hackage.haskell.org/package/base/docs/Data-Foldable.html), 256 | [Traversable](http://hackage.haskell.org/package/base/docs/Data-Traversable.html)), it's quite easy to add an instance for 257 | [MonoFunctor](https://hackage.haskell.org/package/mono-traversable/docs/Data-MonoTraversable.html#t:MonoFunctor), [MonoFoldable](https://hackage.haskell.org/package/mono-traversable/docs/Data-MonoTraversable.html#t:MonoFoldable) or [MonoTraversable](https://hackage.haskell.org/package/mono-traversable/docs/Data-MonoTraversable.html#t:MonoTraversable). 258 | 259 | You just have to declare the proper type instance: 260 | 261 | ``` haskell 262 | {-# LANGUAGE TypeFamilies #-} 263 | 264 | type instance Element (CustomType a) = a 265 | ``` 266 | 267 | And then, we can use the default implementation to declare instances: 268 | 269 | ``` haskell 270 | instance MonoFunctor (CustomType a) 271 | instance MonoFoldable (CustomType a) 272 | instance MonoTraversable (CustomType a) 273 | ``` 274 | 275 | Now you are ready to use ```CustomType a``` with the functions defined in this package. 276 | 277 | **Note**: if your type is a _monomorphic_ container without the proper typeclasses, then you will have to provide an implementation rather than using the default. However, this should be fairly simple, as can be seen [in the code](https://github.com/snoyberg/mono-traversable/blob/d85e4ed3c11afec2d49c0f4fe2812122a279e5d4/src/Data/MonoTraversable.hs#L428) 278 | 279 | 280 | mono-traversable versus lens Traversal 281 | -------------------------------------- 282 | 283 | lens is a library with a lot of functionality covering a variety of patterns. One piece of functionality it exposes is `Fold` and `Traversal` which can also be used to deal with monomorphic containers. 284 | 285 | You could prefer mono-traversable to using this part of lens because 286 | 287 | * Familiar API - If you know `Foldable`, you can use `MonoFoldable` just as easily 288 | * mono-traversable's typeclass based approach means many methods are included in the class but can be given specialised optimized implementations 289 | * You don't explicitly pass around the `Traversal` 290 | 291 | The last point is also a point of inflexibility and points to a use case where you could prefer using a lens `Traversal`. mono-traversable treats `ByteString` as a sequence of bytes. If you want to treat it as both bytes and characters, mono-traversable would require a newtype wrapper around `ByteString`, whereas a lens `Traversal` would use a different traversal function. 292 | 293 | mono-traversable is only an alternative for `Fold` and `Traversal`, not for `Lens`, `Prism`, `Iso`, `Getter`, `Setter`, `Review`, or `Equality`. 294 | 295 | 296 | 297 | 298 | [![Build Status](https://secure.travis-ci.org/snoyberg/mono-traversable.png)](http://travis-ci.org/snoyberg/mono-traversable) 299 | -------------------------------------------------------------------------------- /minlen/src/Data/MinLen.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE TypeFamilies #-} 3 | {-# LANGUAGE UndecidableInstances #-} 4 | {-# LANGUAGE NoImplicitPrelude #-} 5 | {-# LANGUAGE StandaloneDeriving #-} 6 | {-# LANGUAGE GeneralizedNewtypeDeriving #-} 7 | {-# LANGUAGE DeriveDataTypeable #-} 8 | {-# LANGUAGE DeriveFunctor #-} 9 | {-# LANGUAGE FlexibleContexts #-} 10 | {-# LANGUAGE FlexibleInstances #-} 11 | {-# LANGUAGE ScopedTypeVariables #-} 12 | module Data.MinLen 13 | ( -- * Type level naturals 14 | -- ** Peano numbers 15 | -- $peanoNumbers 16 | Zero (..) 17 | , Succ (..) 18 | , TypeNat (..) 19 | , AddNat 20 | , MaxNat 21 | -- * Minimum length newtype wrapper 22 | , MinLen 23 | , unMinLen 24 | , toMinLenZero 25 | , toMinLen 26 | , unsafeToMinLen 27 | , mlcons 28 | , mlappend 29 | , mlunion 30 | , head 31 | , last 32 | , tailML 33 | , initML 34 | , GrowingAppend 35 | , ofoldMap1 36 | , ofold1 37 | , ofoldr1 38 | , ofoldl1' 39 | , maximum 40 | , minimum 41 | , maximumBy 42 | , minimumBy 43 | ) where 44 | 45 | import Prelude (Num (..), Maybe (..), Int, Ordering (..), Eq, Ord (..), Read, Show, Functor (..), ($), flip, const) 46 | import Data.Data (Data) 47 | import Data.Typeable (Typeable) 48 | import Control.Category 49 | import Data.MonoTraversable 50 | import Data.Sequences 51 | import Data.Monoid (Monoid (..)) 52 | import Data.Semigroup (Semigroup (..)) 53 | import Control.Monad.Trans.State.Strict (evalState, state) 54 | 55 | -- $peanoNumbers 56 | -- are a simple way to 57 | -- represent natural numbers (0, 1, 2...) using only a 'Zero' value and a 58 | -- successor function ('Succ'). Each application of 'Succ' increases the number 59 | -- by 1, so @Succ Zero@ is 1, @Succ (Succ Zero)@ is 2, etc. 60 | 61 | -- | 'Zero' is the base value for the Peano numbers. 62 | data Zero = Zero 63 | 64 | -- | 'Succ' represents the next number in the sequence of natural numbers. 65 | -- 66 | -- It takes a @nat@ (a natural number) as an argument. 67 | -- 68 | -- 'Zero' is a @nat@, allowing @'Succ' 'Zero'@ to represent 1. 69 | -- 70 | -- 'Succ' is also a @nat@, so it can be applied to itself, allowing 71 | -- @'Succ' ('Succ' 'Zero')@ to represent 2, 72 | -- @'Succ' ('Succ' ('Succ' 'Zero'))@ to represent 3, and so on. 73 | data Succ nat = Succ nat 74 | 75 | -- | Type-level natural number utility typeclass 76 | class TypeNat nat where 77 | -- | Turn a type-level natural number into a number 78 | -- 79 | -- @ 80 | -- > 'toValueNat' 'Zero' 81 | -- 0 82 | -- > 'toValueNat' ('Succ' ('Succ' ('Succ' 'Zero'))) 83 | -- 3 84 | -- @ 85 | toValueNat :: Num i => nat -> i 86 | 87 | -- | Get a data representation of a natural number type 88 | -- 89 | -- @ 90 | -- > 'typeNat' :: 'Succ' ('Succ' 'Zero') 91 | -- Succ (Succ Zero) -- Errors because Succ and Zero have no Show typeclass, 92 | -- -- But this is what it would look like if it did. 93 | -- @ 94 | typeNat :: nat 95 | 96 | instance TypeNat Zero where 97 | toValueNat Zero = 0 98 | typeNat = Zero 99 | instance TypeNat nat => TypeNat (Succ nat) where 100 | toValueNat (Succ nat) = 1 + toValueNat nat 101 | typeNat = Succ typeNat 102 | 103 | -- | Adds two type-level naturals. 104 | -- 105 | -- See the 'mlappend' type signature for an example. 106 | -- 107 | -- @ 108 | -- > :t 'typeNat' :: 'AddNat' ('Succ' ('Succ' 'Zero')) ('Succ' 'Zero') 109 | -- 110 | -- 'typeNat' :: 'AddNat' ('Succ' ('Succ' 'Zero')) ('Succ' 'Zero') 111 | -- :: 'Succ' ('Succ' ('Succ' 'Zero')) 112 | -- @ 113 | type family AddNat x y 114 | type instance AddNat Zero y = y 115 | type instance AddNat (Succ x) y = AddNat x (Succ y) 116 | 117 | -- | Calculates the maximum of two type-level naturals. 118 | -- 119 | -- See the 'mlunion' type signature for an example. 120 | -- 121 | -- @ 122 | -- > :t 'typeNat' :: 'MaxNat' ('Succ' ('Succ' 'Zero')) ('Succ' 'Zero') 123 | -- 124 | -- 'typeNat' :: 'MaxNat' ('Succ' ('Succ' 'Zero')) ('Succ' 'Zero') 125 | -- :: 'Succ' ('Succ' 'Zero') 126 | -- @ 127 | type family MaxNat x y 128 | type instance MaxNat Zero y = y 129 | type instance MaxNat x Zero = x 130 | type instance MaxNat (Succ x) (Succ y) = Succ (MaxNat x y) 131 | 132 | -- | A wrapper around a container which encodes its minimum length in the type system. 133 | -- This allows functions like 'head' and 'maximum' to be made safe without using 'Maybe'. 134 | -- 135 | -- The length, @nat@, is encoded as a , 136 | -- which starts with the 'Zero' constructor and is made one larger with each application 137 | -- of 'Succ' ('Zero' for 0, @'Succ' 'Zero'@ for 1, @'Succ' ('Succ' 'Zero')@ for 2, etc.). 138 | -- Functions which require at least one element, then, are typed with @Succ nat@, 139 | -- where @nat@ is either 'Zero' or any number of applications of 'Succ': 140 | -- 141 | -- @ 142 | -- 'head' :: 'MonoTraversable' mono => 'MinLen' ('Succ' nat) mono -> 'Element' mono 143 | -- @ 144 | -- 145 | -- The length is also a , 146 | -- i.e. it is only used on the left hand side of the type and doesn't exist at runtime. 147 | -- Notice how @'Succ' 'Zero'@ isn't included in the printed output: 148 | -- 149 | -- @ 150 | -- > 'toMinLen' [1,2,3] :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 151 | -- 'Just' ('MinLen' {unMinLen = [1,2,3]}) 152 | -- @ 153 | -- 154 | -- You can still use GHCI's @:i@ command to see the phantom type information: 155 | -- 156 | -- @ 157 | -- > let xs = 'mlcons' 1 $ 'toMinLenZero' [] 158 | -- > :i xs 159 | -- xs :: 'Num' t => 'MinLen' ('Succ' 'Zero') [t] 160 | -- @ 161 | newtype MinLen nat mono = 162 | MinLen { 163 | unMinLen :: mono -- ^ Get the monomorphic container out of a 'MinLen' wrapper. 164 | } deriving (Eq, Ord, Read, Show, Data, Typeable) 165 | 166 | type instance Element (MinLen nat mono) = Element mono 167 | deriving instance MonoFunctor mono => MonoFunctor (MinLen nat mono) 168 | deriving instance MonoFoldable mono => MonoFoldable (MinLen nat mono) 169 | instance MonoTraversable mono => MonoTraversable (MinLen nat mono) where 170 | otraverse f (MinLen x) = fmap MinLen (otraverse f x) 171 | {-# INLINE otraverse #-} 172 | deriving instance GrowingAppend mono => GrowingAppend (MinLen nat mono) 173 | 174 | -- | This function is unsafe, and must not be exposed from this module. 175 | unsafeMap :: (mono -> mono) -> MinLen nat mono -> MinLen nat mono 176 | unsafeMap f (MinLen x) = MinLen (f x) 177 | 178 | instance (Semigroup mono, GrowingAppend mono) => Semigroup (MinLen nat mono) where 179 | MinLen x <> MinLen y = MinLen (x <> y) 180 | 181 | instance SemiSequence seq => SemiSequence (MinLen nat seq) where 182 | type Index (MinLen nat seq) = Index seq 183 | 184 | intersperse e = unsafeMap $ intersperse e 185 | reverse = unsafeMap reverse 186 | find f = find f . unMinLen 187 | cons x = unsafeMap $ cons x 188 | snoc xs x = unsafeMap (flip snoc x) xs 189 | sortBy f = unsafeMap $ sortBy f 190 | 191 | instance MonoPointed mono => MonoPointed (MinLen Zero mono) where 192 | opoint = MinLen . opoint 193 | {-# INLINE opoint #-} 194 | instance MonoPointed mono => MonoPointed (MinLen (Succ Zero) mono) where 195 | opoint = MinLen . opoint 196 | {-# INLINE opoint #-} 197 | 198 | -- | Get the 'typeNat' of a 'MinLen' container. 199 | natProxy :: TypeNat nat => MinLen nat mono -> nat 200 | natProxy _ = typeNat 201 | 202 | -- | Types a container as having a minimum length of zero. This is useful when combined with other 'MinLen' 203 | -- functions that increase the size of the container. 204 | -- 205 | -- ==== __Examples__ 206 | -- 207 | -- @ 208 | -- > 1 \`mlcons` 'toMinLenZero' [] 209 | -- 'MinLen' {unMinLen = [1]} 210 | -- @ 211 | toMinLenZero :: (MonoFoldable mono) => mono -> MinLen Zero mono 212 | toMinLenZero = MinLen 213 | 214 | -- | Attempts to add a 'MinLen' constraint to a monomorphic container. 215 | -- 216 | -- ==== __Examples__ 217 | -- 218 | -- @ 219 | -- > let xs = 'toMinLen' [1,2,3] :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 220 | -- > xs 221 | -- 'Just' ('MinLen' {unMinLen = [1,2,3]}) 222 | -- 223 | -- > :i xs 224 | -- xs :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 225 | -- @ 226 | -- 227 | -- @ 228 | -- > 'toMinLen' [] :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 229 | -- 'Nothing' 230 | -- @ 231 | toMinLen :: (MonoFoldable mono, TypeNat nat) => mono -> Maybe (MinLen nat mono) 232 | toMinLen mono = 233 | case ocompareLength mono (toValueNat nat :: Int) of 234 | LT -> Nothing 235 | _ -> Just res' 236 | where 237 | nat = natProxy res' 238 | res' = MinLen mono 239 | 240 | -- | __Unsafe__ 241 | -- 242 | -- Although this function itself cannot cause a segfault, it breaks the 243 | -- safety guarantees of 'MinLen' and can lead to a segfault when using 244 | -- otherwise safe functions. 245 | -- 246 | -- ==== __Examples__ 247 | -- 248 | -- @ 249 | -- > let xs = 'unsafeToMinLen' [] :: 'MinLen' ('Succ' 'Zero') ['Int'] 250 | -- > 'olength' xs 251 | -- 0 252 | -- > 'head' xs 253 | -- *** Exception: Data.MonoTraversable.headEx: empty 254 | -- @ 255 | unsafeToMinLen :: mono -> MinLen nat mono 256 | unsafeToMinLen = MinLen 257 | 258 | infixr 5 `mlcons` 259 | 260 | -- | Adds an element to the front of a list, increasing its minimum length by 1. 261 | -- 262 | -- ==== __Examples__ 263 | -- 264 | -- @ 265 | -- > let xs = 'unsafeToMinLen' [1,2,3] :: 'MinLen' ('Succ' 'Zero') ['Int'] 266 | -- > 0 \`mlcons` xs 267 | -- 'MinLen' {unMinLen = [0,1,2,3]} 268 | -- @ 269 | mlcons :: IsSequence seq => Element seq -> MinLen nat seq -> MinLen (Succ nat) seq 270 | mlcons e (MinLen seq) = MinLen (cons e seq) 271 | {-# INLINE mlcons #-} 272 | 273 | -- | Concatenate two sequences, adding their minimum lengths together. 274 | -- 275 | -- ==== __Examples__ 276 | -- 277 | -- @ 278 | -- > let xs = 'unsafeToMinLen' [1,2,3] :: 'MinLen' ('Succ' 'Zero') ['Int'] 279 | -- > xs \`mlappend` xs 280 | -- 'MinLen' {unMinLen = [1,2,3,1,2,3]} 281 | -- @ 282 | mlappend :: IsSequence seq => MinLen x seq -> MinLen y seq -> MinLen (AddNat x y) seq 283 | mlappend (MinLen x) (MinLen y) = MinLen (x `mappend` y) 284 | {-# INLINE mlappend #-} 285 | 286 | -- | Return the first element of a monomorphic container. 287 | -- 288 | -- Safe version of 'headEx', only works on monomorphic containers wrapped in a 289 | -- @'MinLen' ('Succ' nat)@. 290 | head :: MonoFoldable mono => MinLen (Succ nat) mono -> Element mono 291 | head = headEx . unMinLen 292 | {-# INLINE head #-} 293 | 294 | -- | Return the last element of a monomorphic container. 295 | -- 296 | -- Safe version of 'lastEx', only works on monomorphic containers wrapped in a 297 | -- @'MinLen' ('Succ' nat)@. 298 | last :: MonoFoldable mono => MinLen (Succ nat) mono -> Element mono 299 | last = lastEx . unMinLen 300 | {-# INLINE last #-} 301 | 302 | -- | Returns all but the first element of a sequence, reducing its 'MinLen' by 1. 303 | -- 304 | -- Safe, only works on sequences wrapped in a @'MinLen' ('Succ' nat)@. 305 | -- 306 | -- ==== __Examples__ 307 | -- 308 | -- @ 309 | -- > let xs = 'toMinLen' [1,2,3] :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 310 | -- > 'fmap' 'tailML' xs 311 | -- 'Just' ('MinLen' {unMinLen = [2,3]}) 312 | -- @ 313 | tailML :: IsSequence seq => MinLen (Succ nat) seq -> MinLen nat seq 314 | tailML = MinLen . tailEx . unMinLen 315 | 316 | -- | Returns all but the last element of a sequence, reducing its 'MinLen' by 1. 317 | -- 318 | -- Safe, only works on sequences wrapped in a @'MinLen' ('Succ' nat)@. 319 | -- 320 | -- ==== __Examples__ 321 | -- 322 | -- @ 323 | -- > let xs = 'toMinLen' [1,2,3] :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 324 | -- > 'fmap' 'initML' xs 325 | -- 'Just' ('MinLen' {unMinLen = [1,2]}) 326 | -- @ 327 | initML :: IsSequence seq => MinLen (Succ nat) seq -> MinLen nat seq 328 | initML = MinLen . initEx . unMinLen 329 | 330 | -- | Joins two semigroups, keeping the larger 'MinLen' of the two. 331 | -- 332 | -- ==== __Examples__ 333 | -- 334 | -- @ 335 | -- > let xs = 'unsafeToMinLen' [1] :: 'MinLen' ('Succ' 'Zero') ['Int'] 336 | -- > let ys = xs \`mlunion` xs 337 | -- > ys 338 | -- 'MinLen' {unMinLen = [1,1]} 339 | -- 340 | -- > :i ys 341 | -- ys :: 'MinLen' ('Succ' 'Zero') ['Int'] 342 | -- @ 343 | mlunion :: (Semigroup mono, GrowingAppend mono) => MinLen x mono -> MinLen y mono -> MinLen (MaxNat x y) mono 344 | mlunion (MinLen x) (MinLen y) = MinLen (x <> y) 345 | 346 | -- | Map each element of a monomorphic container to a semigroup, and combine the 347 | -- results. 348 | -- 349 | -- Safe version of 'ofoldMap1Ex', only works on monomorphic containers wrapped in a 350 | -- @'MinLen' ('Succ' nat)@. 351 | -- 352 | -- ==== __Examples__ 353 | -- 354 | -- @ 355 | -- > let xs = ("hello", 1 :: 'Integer') \`mlcons` (" world", 2) \`mlcons` ('toMinLenZero' []) 356 | -- > 'ofoldMap1' 'fst' xs 357 | -- "hello world" 358 | -- @ 359 | ofoldMap1 :: (MonoFoldable mono, Semigroup m) => (Element mono -> m) -> MinLen (Succ nat) mono -> m 360 | ofoldMap1 f = ofoldMap1Ex f . unMinLen 361 | {-# INLINE ofoldMap1 #-} 362 | 363 | -- | Join a monomorphic container, whose elements are 'Semigroup's, together. 364 | -- 365 | -- Safe, only works on monomorphic containers wrapped in a @'MinLen' ('Succ' nat)@. 366 | -- 367 | -- ==== __Examples__ 368 | -- 369 | -- @ 370 | -- > let xs = "a" \`mlcons` "b" \`mlcons` "c" \`mlcons` ('toMinLenZero' []) 371 | -- > xs 372 | -- 'MinLen' {unMinLen = ["a","b","c"]} 373 | -- 374 | -- > 'ofold1' xs 375 | -- "abc" 376 | -- @ 377 | ofold1 :: (MonoFoldable mono, Semigroup (Element mono)) => MinLen (Succ nat) mono -> Element mono 378 | ofold1 = ofoldMap1 id 379 | {-# INLINE ofold1 #-} 380 | 381 | -- | Right-associative fold of a monomorphic container with no base element. 382 | -- 383 | -- Safe version of 'ofoldr1Ex', only works on monomorphic containers wrapped in a 384 | -- @'MinLen' ('Succ' nat)@. 385 | -- 386 | -- @'foldr1' f = "Prelude".'Prelude.foldr1' f . 'otoList'@ 387 | -- 388 | -- ==== __Examples__ 389 | -- 390 | -- @ 391 | -- > let xs = "a" \`mlcons` "b" \`mlcons` "c" \`mlcons` ('toMinLenZero' []) 392 | -- > 'ofoldr1' (++) xs 393 | -- "abc" 394 | -- @ 395 | ofoldr1 :: MonoFoldable mono 396 | => (Element mono -> Element mono -> Element mono) 397 | -> MinLen (Succ nat) mono 398 | -> Element mono 399 | ofoldr1 f = ofoldr1Ex f . unMinLen 400 | {-# INLINE ofoldr1 #-} 401 | 402 | -- | Strict left-associative fold of a monomorphic container with no base 403 | -- element. 404 | -- 405 | -- Safe version of 'ofoldl1Ex'', only works on monomorphic containers wrapped in a 406 | -- @'MinLen' ('Succ' nat)@. 407 | -- 408 | -- @'foldl1'' f = "Prelude".'Prelude.foldl1'' f . 'otoList'@ 409 | -- 410 | -- ==== __Examples__ 411 | -- 412 | -- @ 413 | -- > let xs = "a" \`mlcons` "b" \`mlcons` "c" \`mlcons` ('toMinLenZero' []) 414 | -- > 'ofoldl1'' (++) xs 415 | -- "abc" 416 | -- @ 417 | ofoldl1' :: MonoFoldable mono 418 | => (Element mono -> Element mono -> Element mono) 419 | -> MinLen (Succ nat) mono 420 | -> Element mono 421 | ofoldl1' f = ofoldl1Ex' f . unMinLen 422 | {-# INLINE ofoldl1' #-} 423 | 424 | -- | Get the maximum element of a monomorphic container. 425 | -- 426 | -- Safe version of 'maximumEx', only works on monomorphic containers wrapped in a 427 | -- @'MinLen' ('Succ' nat)@. 428 | -- 429 | -- ==== __Examples__ 430 | -- 431 | -- @ 432 | -- > let xs = 'toMinLen' [1,2,3] :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 433 | -- > 'fmap' 'maximum' xs 434 | -- 'Just' 3 435 | -- @ 436 | maximum :: (MonoFoldable mono, Ord (Element mono)) 437 | => MinLen (Succ nat) mono 438 | -> Element mono 439 | maximum = maximumEx . unMinLen 440 | {-# INLINE maximum #-} 441 | 442 | -- | Get the minimum element of a monomorphic container. 443 | -- 444 | -- Safe version of 'minimumEx', only works on monomorphic containers wrapped in a 445 | -- @'MinLen' ('Succ' nat)@. 446 | -- 447 | -- ==== __Examples__ 448 | -- 449 | -- @ 450 | -- > let xs = 'toMinLen' [1,2,3] :: 'Maybe' ('MinLen' ('Succ' 'Zero') ['Int']) 451 | -- > 'fmap' 'minimum' xs 452 | -- 'Just' 1 453 | -- @ 454 | minimum :: (MonoFoldable mono, Ord (Element mono)) 455 | => MinLen (Succ nat) mono 456 | -> Element mono 457 | minimum = minimumEx . unMinLen 458 | {-# INLINE minimum #-} 459 | 460 | -- | Get the maximum element of a monomorphic container, 461 | -- using a supplied element ordering function. 462 | -- 463 | -- Safe version of 'maximumByEx', only works on monomorphic containers wrapped in a 464 | -- @'MinLen' ('Succ' nat)@. 465 | maximumBy :: MonoFoldable mono 466 | => (Element mono -> Element mono -> Ordering) 467 | -> MinLen (Succ nat) mono 468 | -> Element mono 469 | maximumBy cmp = maximumByEx cmp . unMinLen 470 | {-# INLINE maximumBy #-} 471 | 472 | -- | Get the minimum element of a monomorphic container, 473 | -- using a supplied element ordering function. 474 | -- 475 | -- Safe version of 'minimumByEx', only works on monomorphic containers wrapped in a 476 | -- @'MinLen' ('Succ' nat)@. 477 | minimumBy :: MonoFoldable mono 478 | => (Element mono -> Element mono -> Ordering) 479 | -> MinLen (Succ nat) mono 480 | -> Element mono 481 | minimumBy cmp = minimumByEx cmp . unMinLen 482 | {-# INLINE minimumBy #-} 483 | 484 | -- | 'oextract' is 'head'. 485 | -- 486 | -- For @'oextend' f@, the new 'mono' is populated by applying @f@ to 487 | -- successive 'tail's of the original 'mono'. 488 | -- 489 | -- For example, for @'MinLen' ('Succ' 'Zero') ['Int']@, or 490 | -- @'NonNull' ['Int']@: 491 | -- 492 | -- @ 493 | -- 'oextend' f [1,2,3,4,5] = [ f [1, 2, 3, 4, 5] 494 | -- , f [2, 3, 4, 5] 495 | -- , f [3, 4, 5] 496 | -- , f [4, 5] 497 | -- , f [5] 498 | -- ] 499 | -- @ 500 | -- 501 | -- Meant to be a direct analogy to the instance for 'NonEmpty' @a@. 502 | -- 503 | instance IsSequence mono 504 | => MonoComonad (MinLen (Succ Zero) mono) where 505 | oextract = head 506 | oextend f (MinLen mono) = MinLen 507 | . flip evalState mono 508 | . ofor mono 509 | . const 510 | . state 511 | $ \mono' -> (f (MinLen mono'), tailEx mono') 512 | -------------------------------------------------------------------------------- /classy-prelude/src/ClassyPrelude.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE CPP #-} 2 | {-# LANGUAGE NoImplicitPrelude #-} 3 | {-# LANGUAGE FlexibleContexts #-} 4 | {-# LANGUAGE TypeFamilies #-} 5 | module ClassyPrelude 6 | ( -- * CorePrelude 7 | module CorePrelude 8 | , undefined 9 | -- * Standard 10 | -- ** Monoid 11 | , (++) 12 | -- ** Semigroup 13 | , Semigroup (..) 14 | , WrappedMonoid 15 | -- ** Functor 16 | , module Data.Functor 17 | -- ** Applicative 18 | , module Control.Applicative 19 | , (<&&>) 20 | , (<||>) 21 | -- ** Monad 22 | , module Control.Monad 23 | , whenM 24 | , unlessM 25 | -- ** UnliftIO reexports 26 | , module UnliftIO 27 | -- ** Mutable references 28 | , orElseSTM 29 | , module Data.Mutable 30 | -- ** STM Channels 31 | , module Control.Concurrent.STM.TBChan 32 | , module Control.Concurrent.STM.TBMChan 33 | , module Control.Concurrent.STM.TBMQueue 34 | , module Control.Concurrent.STM.TMChan 35 | , module Control.Concurrent.STM.TMQueue 36 | -- ** Primitive (exported since 0.9.4) 37 | , primToPrim 38 | , primToIO 39 | , primToST 40 | , module Data.Primitive.MutVar 41 | -- ** Debugging 42 | , trace 43 | , traceShow 44 | , traceId 45 | , traceM 46 | , traceShowId 47 | , traceShowM 48 | -- ** Time (since 0.6.1) 49 | , module Data.Time 50 | #if MIN_VERSION_time(1,10,0) 51 | , parseTime 52 | #endif 53 | -- ** Generics (since 0.8.1) 54 | , Generic 55 | -- ** Transformers (since 0.9.4) 56 | , Identity (..) 57 | , MonadReader 58 | , ask 59 | , asks 60 | , ReaderT (..) 61 | , Reader 62 | -- * Poly hierarchy 63 | , module Data.Foldable 64 | , module Data.Traversable 65 | -- ** Bifunctor (since 0.10.0) 66 | , module Data.Bifunctor 67 | -- * Mono hierarchy 68 | , module Data.MonoTraversable 69 | , module Data.MonoTraversable.Unprefixed 70 | , module Data.Sequences 71 | , module Data.Containers 72 | , module Data.Builder 73 | , module Data.NonNull 74 | , toByteVector 75 | , fromByteVector 76 | -- * I\/O 77 | , module Say 78 | -- * Concurrency 79 | , yieldThread 80 | , waitAsync 81 | , pollAsync 82 | , waitCatchAsync 83 | , linkAsync 84 | , link2Async 85 | -- * Non-standard 86 | -- ** List-like classes 87 | , map 88 | --, split 89 | , readMay 90 | , zip, zip3, zip4, zip5, zip6, zip7 91 | , unzip, unzip3, unzip4, unzip5, unzip6, unzip7 92 | , zipWith, zipWith3, zipWith4, zipWith5, zipWith6, zipWith7 93 | 94 | , hashNub 95 | , ordNub 96 | , ordNubBy 97 | 98 | , sortWith 99 | , Prelude.repeat 100 | -- ** Set-like 101 | , (\\) 102 | , intersect 103 | -- FIXME , mapSet 104 | -- ** Text-like 105 | , Show (..) 106 | , tshow 107 | , tlshow 108 | -- *** Case conversion 109 | , charToLower 110 | , charToUpper 111 | -- ** IO 112 | , readFile 113 | , readFileUtf8 114 | , writeFile 115 | , writeFileUtf8 116 | , hGetContents 117 | , hPut 118 | , hGetChunk 119 | , print 120 | -- Prelude IO operations 121 | , putChar 122 | , putStr 123 | , putStrLn 124 | , getChar 125 | , getLine 126 | , getContents 127 | , interact 128 | -- ** Difference lists 129 | , DList 130 | , asDList 131 | , applyDList 132 | -- ** Exceptions 133 | , module Control.DeepSeq 134 | -- ** Force types 135 | -- | Helper functions for situations where type inferer gets confused. 136 | , asByteString 137 | , asLByteString 138 | , asHashMap 139 | , asHashSet 140 | , asText 141 | , asLText 142 | , asList 143 | , asMap 144 | , asIntMap 145 | , asMaybe 146 | , asSet 147 | , asIntSet 148 | , asVector 149 | , asUVector 150 | , asSVector 151 | , asString 152 | ) where 153 | 154 | import qualified Prelude 155 | import Control.Applicative ((<**>),liftA,liftA2,liftA3,Alternative (..), optional) 156 | import Data.Functor hiding (unzip) 157 | import Control.Exception (assert) 158 | import Control.DeepSeq (deepseq, ($!!), force, NFData (..)) 159 | import Control.Monad (when, unless, void, liftM, ap, forever, join, replicateM_, guard, MonadPlus (..), (=<<), (>=>), (<=<), liftM2, liftM3, liftM4, liftM5) 160 | import qualified Control.Concurrent.STM as STM 161 | import Data.Mutable 162 | import Data.Traversable (Traversable (..), for, forM) 163 | import Data.Foldable (Foldable) 164 | import UnliftIO 165 | 166 | import Data.Vector.Instances () 167 | import CorePrelude hiding 168 | ( putStr, putStrLn, print, undefined, (<>), catMaybes, first, second 169 | , catchIOError 170 | ) 171 | import Data.ChunkedZip 172 | import qualified Data.Char as Char 173 | import Data.Sequences 174 | import Data.MonoTraversable 175 | import Data.MonoTraversable.Unprefixed 176 | import Data.MonoTraversable.Instances () 177 | import Data.Containers 178 | import Data.Builder 179 | import Data.NonNull 180 | import qualified Data.ByteString 181 | import qualified Data.Text.IO as TextIO 182 | import qualified Data.Text.Lazy.IO as LTextIO 183 | import Data.ByteString.Internal (ByteString (PS)) 184 | import Data.ByteString.Lazy.Internal (defaultChunkSize) 185 | import Data.Vector.Storable (unsafeToForeignPtr, unsafeFromForeignPtr) 186 | 187 | import qualified Debug.Trace as Trace 188 | import Data.Semigroup (Semigroup (..), WrappedMonoid (..)) 189 | import Prelude (Show (..)) 190 | import Data.Time 191 | ( UTCTime (..) 192 | , Day (..) 193 | , toGregorian 194 | , fromGregorian 195 | , formatTime 196 | #if !MIN_VERSION_time(1,10,0) 197 | , parseTime 198 | #endif 199 | , parseTimeM 200 | , getCurrentTime 201 | , defaultTimeLocale 202 | ) 203 | import qualified Data.Time as Time 204 | 205 | import qualified Data.Set as Set 206 | import qualified Data.Map as Map 207 | import qualified Data.HashSet as HashSet 208 | 209 | import GHC.Generics (Generic) 210 | import GHC.Stack (HasCallStack) 211 | 212 | import Control.Monad.Primitive (primToPrim, primToIO, primToST) 213 | import Data.Primitive.MutVar 214 | 215 | import Data.Functor.Identity (Identity (..)) 216 | import Control.Monad.Reader (MonadReader, ask, asks, ReaderT (..), Reader) 217 | import Data.Bifunctor 218 | import Data.DList (DList) 219 | import qualified Data.DList as DList 220 | import Say 221 | import Control.Concurrent.STM.TBChan 222 | import Control.Concurrent.STM.TBMChan 223 | import Control.Concurrent.STM.TBMQueue 224 | import Control.Concurrent.STM.TMChan 225 | import Control.Concurrent.STM.TMQueue 226 | import qualified Control.Concurrent 227 | 228 | tshow :: Show a => a -> Text 229 | tshow = fromList . Prelude.show 230 | 231 | tlshow :: Show a => a -> LText 232 | tlshow = fromList . Prelude.show 233 | 234 | -- | Convert a character to lower case. 235 | -- 236 | -- Character-based case conversion is lossy in comparison to string-based 'Data.MonoTraversable.toLower'. 237 | -- For instance, İ will be converted to i, instead of i̇. 238 | charToLower :: Char -> Char 239 | charToLower = Char.toLower 240 | 241 | -- | Convert a character to upper case. 242 | -- 243 | -- Character-based case conversion is lossy in comparison to string-based 'Data.MonoTraversable.toUpper'. 244 | -- For instance, ß won't be converted to SS. 245 | charToUpper :: Char -> Char 246 | charToUpper = Char.toUpper 247 | 248 | readMay :: (Element c ~ Char, MonoFoldable c, Read a) => c -> Maybe a 249 | readMay a = -- FIXME replace with safe-failure stuff 250 | case [x | (x, t) <- Prelude.reads (otoList a :: String), onull t] of 251 | [x] -> Just x 252 | _ -> Nothing 253 | 254 | map :: Functor f => (a -> b) -> f a -> f b 255 | map = fmap 256 | 257 | infixr 5 ++ 258 | (++) :: Monoid m => m -> m -> m 259 | (++) = mappend 260 | {-# INLINE (++) #-} 261 | 262 | infixl 9 \\{-This comment teaches CPP correct behaviour -} 263 | -- | An alias for 'difference'. 264 | (\\) :: SetContainer a => a -> a -> a 265 | (\\) = difference 266 | {-# INLINE (\\) #-} 267 | 268 | -- | An alias for 'intersection'. 269 | intersect :: SetContainer a => a -> a -> a 270 | intersect = intersection 271 | {-# INLINE intersect #-} 272 | 273 | asByteString :: ByteString -> ByteString 274 | asByteString = id 275 | 276 | asLByteString :: LByteString -> LByteString 277 | asLByteString = id 278 | 279 | asHashMap :: HashMap k v -> HashMap k v 280 | asHashMap = id 281 | 282 | asHashSet :: HashSet a -> HashSet a 283 | asHashSet = id 284 | 285 | asText :: Text -> Text 286 | asText = id 287 | 288 | asLText :: LText -> LText 289 | asLText = id 290 | 291 | asList :: [a] -> [a] 292 | asList = id 293 | 294 | asMap :: Map k v -> Map k v 295 | asMap = id 296 | 297 | asIntMap :: IntMap v -> IntMap v 298 | asIntMap = id 299 | 300 | asMaybe :: Maybe a -> Maybe a 301 | asMaybe = id 302 | 303 | asSet :: Set a -> Set a 304 | asSet = id 305 | 306 | asIntSet :: IntSet -> IntSet 307 | asIntSet = id 308 | 309 | asVector :: Vector a -> Vector a 310 | asVector = id 311 | 312 | asUVector :: UVector a -> UVector a 313 | asUVector = id 314 | 315 | asSVector :: SVector a -> SVector a 316 | asSVector = id 317 | 318 | asString :: [Char] -> [Char] 319 | asString = id 320 | 321 | print :: (Show a, MonadIO m) => a -> m () 322 | print = liftIO . Prelude.print 323 | 324 | -- | Sort elements using the user supplied function to project something out of 325 | -- each element. 326 | -- Inspired by . 327 | sortWith :: (Ord a, IsSequence c) => (Element c -> a) -> c -> c 328 | sortWith f = sortBy $ comparing f 329 | 330 | -- | We define our own 'undefined' which is marked as deprecated. This makes it 331 | -- useful to use during development, but lets you more easily get 332 | -- notifications if you accidentally ship partial code in production. 333 | -- 334 | -- The classy prelude recommendation for when you need to really have a partial 335 | -- function in production is to use 'error' with a very descriptive message so 336 | -- that, in case an exception is thrown, you get more information than 337 | -- @"Prelude".'Prelude.undefined'@. 338 | -- 339 | -- Since 0.5.5 340 | undefined :: HasCallStack => a 341 | undefined = error "ClassyPrelude.undefined" 342 | {-# DEPRECATED undefined "It is highly recommended that you either avoid partial functions or provide meaningful error messages" #-} 343 | 344 | -- | We define our own 'trace' (and also its variants) which provides a warning 345 | -- when used. So that tracing is available during development, but the compiler 346 | -- reminds you to not leave them in the code for production. 347 | {-# WARNING trace "Leaving traces in the code" #-} 348 | trace :: String -> a -> a 349 | trace = Trace.trace 350 | 351 | {-# WARNING traceShow "Leaving traces in the code" #-} 352 | traceShow :: Show a => a -> b -> b 353 | traceShow = Trace.traceShow 354 | 355 | -- | 356 | -- 357 | -- Since 0.5.9 358 | {-# WARNING traceId "Leaving traces in the code" #-} 359 | traceId :: String -> String 360 | traceId a = Trace.trace a a 361 | 362 | -- | 363 | -- 364 | -- Since 0.5.9 365 | {-# WARNING traceM "Leaving traces in the code" #-} 366 | traceM :: (Monad m) => String -> m () 367 | traceM string = Trace.trace string $ return () 368 | 369 | -- | 370 | -- 371 | -- Since 0.5.9 372 | {-# WARNING traceShowId "Leaving traces in the code" #-} 373 | traceShowId :: (Show a) => a -> a 374 | traceShowId a = Trace.trace (show a) a 375 | 376 | -- | 377 | -- 378 | -- Since 0.5.9 379 | {-# WARNING traceShowM "Leaving traces in the code" #-} 380 | traceShowM :: (Show a, Monad m) => a -> m () 381 | traceShowM = traceM . show 382 | 383 | -- | Originally 'Conc.yield'. 384 | yieldThread :: MonadIO m => m () 385 | yieldThread = liftIO Control.Concurrent.yield 386 | {-# INLINE yieldThread #-} 387 | 388 | -- Below is a lot of coding for classy-prelude! 389 | -- These functions are restricted to lists right now. 390 | -- Should eventually exist in mono-foldable and be extended to MonoFoldable 391 | -- when doing that should re-run the haskell-ordnub benchmarks 392 | 393 | -- | same behavior as 'Data.List.nub', but requires 'Hashable' & 'Eq' and is @O(n log n)@ 394 | -- 395 | -- 396 | hashNub :: (Hashable a, Eq a) => [a] -> [a] 397 | hashNub = go HashSet.empty 398 | where 399 | go _ [] = [] 400 | go s (x:xs) | x `HashSet.member` s = go s xs 401 | | otherwise = x : go (HashSet.insert x s) xs 402 | 403 | -- | same behavior as 'Data.List.nub', but requires 'Ord' and is @O(n log n)@ 404 | -- 405 | -- 406 | ordNub :: (Ord a) => [a] -> [a] 407 | ordNub = go Set.empty 408 | where 409 | go _ [] = [] 410 | go s (x:xs) | x `Set.member` s = go s xs 411 | | otherwise = x : go (Set.insert x s) xs 412 | 413 | -- | same behavior as 'Data.List.nubBy', but requires 'Ord' and is @O(n log n)@ 414 | -- 415 | -- 416 | ordNubBy :: (Ord b) => (a -> b) -> (a -> a -> Bool) -> [a] -> [a] 417 | ordNubBy p f = go Map.empty 418 | -- When removing duplicates, the first function assigns the input to a bucket, 419 | -- the second function checks whether it is already in the bucket (linear search). 420 | where 421 | go _ [] = [] 422 | go m (x:xs) = let b = p x in case b `Map.lookup` m of 423 | Nothing -> x : go (Map.insert b [x] m) xs 424 | Just bucket 425 | | elem_by f x bucket -> go m xs 426 | | otherwise -> x : go (Map.insert b (x:bucket) m) xs 427 | 428 | -- From the Data.List source code. 429 | elem_by :: (a -> a -> Bool) -> a -> [a] -> Bool 430 | elem_by _ _ [] = False 431 | elem_by eq y (x:xs) = y `eq` x || elem_by eq y xs 432 | 433 | -- | Synonym for 'STM.orElse'. 434 | orElseSTM :: STM a -> STM a -> STM a 435 | orElseSTM = STM.orElse 436 | {-# INLINE orElseSTM #-} 437 | 438 | -- | Only perform the action if the predicate returns 'True'. 439 | -- 440 | -- Since 0.9.2 441 | whenM :: Monad m => m Bool -> m () -> m () 442 | whenM mbool action = mbool >>= flip when action 443 | 444 | -- | Only perform the action if the predicate returns 'False'. 445 | -- 446 | -- Since 0.9.2 447 | unlessM :: Monad m => m Bool -> m () -> m () 448 | unlessM mbool action = mbool >>= flip unless action 449 | 450 | -- | Force type to a 'DList' 451 | -- 452 | -- Since 0.11.0 453 | asDList :: DList a -> DList a 454 | asDList = id 455 | {-# INLINE asDList #-} 456 | 457 | -- | Synonym for 'DList.apply' 458 | -- 459 | -- Since 0.11.0 460 | applyDList :: DList a -> [a] -> [a] 461 | applyDList = DList.apply 462 | {-# INLINE applyDList #-} 463 | 464 | infixr 3 <&&> 465 | -- | '&&' lifted to an Applicative. 466 | -- 467 | -- @since 0.12.8 468 | (<&&>) :: Applicative a => a Bool -> a Bool -> a Bool 469 | (<&&>) = liftA2 (&&) 470 | {-# INLINE (<&&>) #-} 471 | 472 | infixr 2 <||> 473 | -- | '||' lifted to an Applicative. 474 | -- 475 | -- @since 0.12.8 476 | (<||>) :: Applicative a => a Bool -> a Bool -> a Bool 477 | (<||>) = liftA2 (||) 478 | {-# INLINE (<||>) #-} 479 | 480 | -- | Convert a 'ByteString' into a storable 'Vector'. 481 | toByteVector :: ByteString -> SVector Word8 482 | toByteVector (PS fptr offset idx) = unsafeFromForeignPtr fptr offset idx 483 | {-# INLINE toByteVector #-} 484 | 485 | -- | Convert a storable 'Vector' into a 'ByteString'. 486 | fromByteVector :: SVector Word8 -> ByteString 487 | fromByteVector v = 488 | PS fptr offset idx 489 | where 490 | (fptr, offset, idx) = unsafeToForeignPtr v 491 | {-# INLINE fromByteVector #-} 492 | 493 | -- | 'waitSTM' for any 'MonadIO' 494 | -- 495 | -- @since 1.0.0 496 | waitAsync :: MonadIO m => Async a -> m a 497 | waitAsync = atomically . waitSTM 498 | 499 | -- | 'pollSTM' for any 'MonadIO' 500 | -- 501 | -- @since 1.0.0 502 | pollAsync :: MonadIO m => Async a -> m (Maybe (Either SomeException a)) 503 | pollAsync = atomically . pollSTM 504 | 505 | -- | 'waitCatchSTM' for any 'MonadIO' 506 | -- 507 | -- @since 1.0.0 508 | waitCatchAsync :: MonadIO m => Async a -> m (Either SomeException a) 509 | waitCatchAsync = waitCatch 510 | 511 | -- | 'Async.link' generalized to any 'MonadIO' 512 | -- 513 | -- @since 1.0.0 514 | linkAsync :: MonadIO m => Async a -> m () 515 | linkAsync = UnliftIO.link 516 | 517 | -- | 'Async.link2' generalized to any 'MonadIO' 518 | -- 519 | -- @since 1.0.0 520 | link2Async :: MonadIO m => Async a -> Async b -> m () 521 | link2Async a = UnliftIO.link2 a 522 | 523 | -- | Strictly read a file into a 'ByteString'. 524 | -- 525 | -- @since 1.2.0 526 | readFile :: MonadIO m => FilePath -> m ByteString 527 | readFile = liftIO . Data.ByteString.readFile 528 | 529 | -- | Strictly read a file into a 'Text' using a UTF-8 character 530 | -- encoding. In the event of a character encoding error, a Unicode 531 | -- replacement character will be used (a.k.a., @lenientDecode@). 532 | -- 533 | -- @since 1.2.0 534 | readFileUtf8 :: MonadIO m => FilePath -> m Text 535 | readFileUtf8 = liftM decodeUtf8 . readFile 536 | 537 | -- | Write a 'ByteString' to a file. 538 | -- 539 | -- @since 1.2.0 540 | writeFile :: MonadIO m => FilePath -> ByteString -> m () 541 | writeFile fp = liftIO . Data.ByteString.writeFile fp 542 | 543 | -- | Write a 'Text' to a file using a UTF-8 character encoding. 544 | -- 545 | -- @since 1.2.0 546 | writeFileUtf8 :: MonadIO m => FilePath -> Text -> m () 547 | writeFileUtf8 fp = writeFile fp . encodeUtf8 548 | 549 | -- | Strictly read the contents of the given 'Handle' into a 550 | -- 'ByteString'. 551 | -- 552 | -- @since 1.2.0 553 | hGetContents :: MonadIO m => Handle -> m ByteString 554 | hGetContents = liftIO . Data.ByteString.hGetContents 555 | 556 | -- | Write a 'ByteString' to the given 'Handle'. 557 | -- 558 | -- @since 1.2.0 559 | hPut :: MonadIO m => Handle -> ByteString -> m () 560 | hPut h = liftIO . Data.ByteString.hPut h 561 | 562 | -- | Read a single chunk of data as a 'ByteString' from the given 563 | -- 'Handle'. 564 | -- 565 | -- Under the surface, this uses 'Data.ByteString.hGetSome' with the 566 | -- default chunk size. 567 | -- 568 | -- @since 1.2.0 569 | hGetChunk :: MonadIO m => Handle -> m ByteString 570 | hGetChunk = liftIO . flip Data.ByteString.hGetSome defaultChunkSize 571 | 572 | -- | Write a character to stdout 573 | -- 574 | -- Uses system locale settings 575 | -- 576 | -- @since 1.3.1 577 | putChar :: MonadIO m => Char -> m () 578 | putChar = liftIO . Prelude.putChar 579 | 580 | -- | Write a Text to stdout 581 | -- 582 | -- Uses system locale settings 583 | -- 584 | -- @since 1.3.1 585 | putStr :: MonadIO m => Text -> m () 586 | putStr = liftIO . TextIO.putStr 587 | 588 | -- | Write a Text followed by a newline to stdout 589 | -- 590 | -- Uses system locale settings 591 | -- 592 | -- @since 1.3.1 593 | putStrLn :: MonadIO m => Text -> m () 594 | putStrLn = liftIO . TextIO.putStrLn 595 | 596 | -- | Read a character from stdin 597 | -- 598 | -- Uses system locale settings 599 | -- 600 | -- @since 1.3.1 601 | getChar :: MonadIO m => m Char 602 | getChar = liftIO Prelude.getChar 603 | 604 | -- | Read a line from stdin 605 | -- 606 | -- Uses system locale settings 607 | -- 608 | -- @since 1.3.1 609 | getLine :: MonadIO m => m Text 610 | getLine = liftIO TextIO.getLine 611 | 612 | -- | Read all input from stdin into a lazy Text ('LText') 613 | -- 614 | -- Uses system locale settings 615 | -- 616 | -- @since 1.3.1 617 | getContents :: MonadIO m => m LText 618 | getContents = liftIO LTextIO.getContents 619 | 620 | -- | Takes a function of type 'LText -> LText' and passes all input on stdin 621 | -- to it, then prints result to stdout 622 | -- 623 | -- Uses lazy IO 624 | -- Uses system locale settings 625 | -- 626 | -- @since 1.3.1 627 | interact :: MonadIO m => (LText -> LText) -> m () 628 | interact = liftIO . LTextIO.interact 629 | 630 | 631 | #if MIN_VERSION_time(1,10,0) 632 | parseTime 633 | :: Time.ParseTime t 634 | => Time.TimeLocale -- ^ Time locale. 635 | -> String -- ^ Format string. 636 | -> String -- ^ Input string. 637 | -> Maybe t -- ^ The time value, or 'Nothing' if the input could not be parsed using the given format. 638 | parseTime = parseTimeM True 639 | #endif 640 | 641 | 642 | --------------------------------------------------------------------------------