├── .ctags ├── .gitignore ├── .travis.yml ├── .yamllint ├── Data └── Functor │ ├── Foldable.idr │ └── Foldable │ ├── Exotic.idr │ ├── Instances.idr │ └── Mod.idr ├── Justfile ├── LICENSE ├── README.md ├── TODO.md ├── Test └── Spec.idr ├── docs ├── IdrisDoc ├── docs │ ├── Control.Comonad.html │ ├── Control.Monad.Free.html │ ├── Control.Monad.Identity.html │ ├── Data.Functor.Foldable.Exotic.html │ ├── Data.Functor.Foldable.Instances.html │ ├── Data.Functor.Foldable.Mod.html │ ├── Data.Profunctor.Comonad.Cofree.html │ ├── Decidable.Equality.html │ ├── FFI.html │ ├── FFI_C.html │ ├── ForeignEnv.html │ ├── Language.Reflection.Elab.html │ ├── Language.Reflection.html │ ├── Prelude.Algebra.html │ ├── Prelude.Basics.html │ ├── Prelude.Bool.html │ ├── Prelude.Either.html │ ├── Prelude.File.html │ ├── Prelude.Foldable.html │ ├── Prelude.Functor.html │ ├── Prelude.Interfaces.html │ ├── Prelude.List.html │ ├── Prelude.Maybe.html │ ├── Prelude.Monad.html │ ├── Prelude.Nat.html │ ├── Prelude.Show.html │ ├── Prelude.Stream.html │ └── [builtins].html ├── index.html └── styles.css ├── elba.toml ├── recursion_schemes.ipkg └── test.ipkg /.ctags: -------------------------------------------------------------------------------- 1 | --langdef=Idris 2 | --langmap=Idris:.idr 3 | --regex-Idris=/^ *([[:lower:]][[:alnum:]_]+)[[:blank:]]*:[^:].*->.*/\1/f,function,functions/ 4 | --regex-Idris=/^ *([[:lower:]][[:alnum:]_]+)[[:blank:]]*:[^:][^-]+$/\1/c,constant,constants/ 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | tags 3 | *.ibc 4 | elba.lock 5 | target 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | sudo: false 3 | language: python 4 | cache: 5 | directories: 6 | - $HOME/.cabal 7 | - $HOME/.ghc 8 | addons: 9 | apt: 10 | sources: 11 | - hvr-ghc 12 | packages: 13 | - libgmp3-dev 14 | - ghc-8.4.3 15 | - cabal-install-2.2 16 | 17 | install: 18 | - rm -rf $HOME/.cabal 19 | - export PATH=/opt/ghc/$GHCVER/bin:$PATH 20 | - export PATH=$HOME/.cabal/bin:$PATH 21 | - cabal update 22 | - mkdir -p $HOME/.cabal/store/ghc-8.4.3/package.db 23 | - travis_wait 40 cabal new-install idris 24 | - git clone https://github.com/pheymann/specdris 25 | - git clone https://github.com/vmchale/comonad 26 | - git clone https://github.com/idris-hackers/idris-free.git 27 | - cd specdris/ 28 | - idris --install specdris.ipkg 29 | - cd ../comonad/ 30 | - idris --install comonad.ipkg 31 | - cd ../idris-free 32 | - idris --install idris-free.ipkg 33 | 34 | script: 35 | - cd ../ 36 | - idris --testpkg test.ipkg 37 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | rules: 4 | braces: 5 | min-spaces-inside: 0 6 | max-spaces-inside: 0 7 | min-spaces-inside-empty: -1 8 | max-spaces-inside-empty: -1 9 | brackets: 10 | min-spaces-inside: 0 11 | max-spaces-inside: 0 12 | min-spaces-inside-empty: -1 13 | max-spaces-inside-empty: -1 14 | colons: 15 | max-spaces-before: 0 16 | max-spaces-after: 1 17 | commas: 18 | max-spaces-before: 0 19 | min-spaces-after: 1 20 | max-spaces-after: 1 21 | comments: 22 | level: warning 23 | require-starting-space: true 24 | min-spaces-from-content: 2 25 | comments-indentation: 26 | level: warning 27 | document-end: disable 28 | document-start: 29 | level: warning 30 | present: true 31 | empty-lines: 32 | max: 2 33 | max-start: 0 34 | max-end: 0 35 | hyphens: 36 | max-spaces-after: 1 37 | indentation: 38 | spaces: consistent 39 | indent-sequences: false 40 | check-multi-line-strings: false 41 | key-duplicates: enable 42 | line-length: disable 43 | new-line-at-end-of-file: enable 44 | new-lines: 45 | type: unix 46 | trailing-spaces: enable 47 | truthy: disable 48 | -------------------------------------------------------------------------------- /Data/Functor/Foldable.idr: -------------------------------------------------------------------------------- 1 | ||| Convenience module that re-exports everything. 2 | module Data.Functor.Foldable 3 | 4 | import public Data.Functor.Foldable.Mod 5 | import public Data.Functor.Foldable.Exotic 6 | import public Data.Functor.Foldable.Instances 7 | -------------------------------------------------------------------------------- /Data/Functor/Foldable/Exotic.idr: -------------------------------------------------------------------------------- 1 | module Data.Functor.Foldable.Exotic 2 | 3 | import Control.Arrow 4 | import Control.Monad.Identity 5 | import Control.Comonad 6 | import Control.Comonad.Cofree 7 | import Data.Functor.Foldable.Mod 8 | import Data.Functor.Foldable.Instances 9 | 10 | %access public export 11 | 12 | infixl 9 .* 13 | 14 | (.*) : (c -> d) -> (a -> b -> c) -> (a -> b -> d) 15 | (.*) f g x y = f (g x y) 16 | 17 | ||| Gibbons' metamorphism. Tear down a structure, transform it, and then build up a new structure 18 | meta : (Functor f, Corecursive f t', Recursive g t) => (a -> f a) -> (b -> a) -> (g b -> b) -> t -> t' 19 | meta f e g = ana f . e . cata g 20 | 21 | ||| Erwig's metamorphism. Essentially a hylomorphism with a natural 22 | ||| transformation in between. This allows us to use more than one functor in a 23 | ||| hylomorphism. 24 | hyloPro : (Functor f, Functor g) => (f a -> a) -> ({c:_} -> g c -> f c) -> (b -> g b) -> b -> a 25 | hyloPro h e k = g 26 | where g x = h . e . map g . k $ x 27 | 28 | ||| A dynamorphism builds up with an anamorphism and tears down with a 29 | ||| histomorphism. Useful for lexical scoping. 30 | dynaPro : (Functor f, Functor g) => (f (Cofree f a) -> a) -> ({c:_} -> g c -> f c) -> (b -> g b) -> b -> a 31 | dynaPro phi eta psi = ghylo distHisto distAna phi (eta . map Id . psi) 32 | 33 | ||| A dynamorphism without a natural transformation in between. 34 | dyna : (Functor f) => (f (Cofree f a) -> a) -> (b -> f b) -> b -> a 35 | dyna phi = dynaPro phi id 36 | 37 | ||| Mendler's catamorphism 38 | mcata : ({y : _} -> ((y -> c) -> f y -> c)) -> Fix f -> c 39 | mcata psi = psi (mcata psi) . unfix 40 | 41 | --Basically, this forms an F-algebra from a loopkup functoin plus a function that gives us the lookup function 42 | ||| Mendler's histomorphism 43 | mhisto : ({y : _} -> ((y -> c) -> (y -> f y) -> f y -> c)) -> Fix f -> c 44 | mhisto psi = psi (mhisto psi) unfix . unfix 45 | 46 | ||| Elgot algebra (see [this paper](https://arxiv.org/abs/cs/0609040)) 47 | elgot : Functor f => (f a -> a) -> (b -> Either a (f b)) -> b -> a 48 | elgot phi psi = h where h = (id `either` phi . map h) . psi 49 | 50 | ||| Anamorphism that allows shortcuts. 51 | micro : (Functor f, Corecursive f a) => (b -> Either a (f b)) -> b -> a 52 | micro = elgot embed 53 | 54 | ||| Elgot coalgebra 55 | coelgot : Functor f => ((a, f b) -> b) -> (a -> f a) -> a -> b 56 | coelgot phi psi = h where h = phi . (\x => (x, (map h . psi) x)) 57 | -------------------------------------------------------------------------------- /Data/Functor/Foldable/Instances.idr: -------------------------------------------------------------------------------- 1 | -- ------------------------------------- [ Data.Functor.Foldable.Instances.idr ] 2 | -- Module : Data.Functor.Foldable.Internal.Instances 3 | -- Description : Instances of 'Recursive' and 'Corecursive' for various 4 | -- things. 5 | -- --------------------------------------------------------------------- [ EOH ] 6 | module Data.Functor.Foldable.Instances 7 | 8 | import Control.Monad.Free 9 | import Data.Functor.Foldable.Mod 10 | 11 | %access public export 12 | 13 | implementation Base Nat Maybe where 14 | 15 | implementation Recursive Maybe Nat where 16 | project Z = Nothing 17 | project (S a) = Just a 18 | 19 | implementation Corecursive Maybe Nat where 20 | embed Nothing = Z 21 | embed (Just a) = S a 22 | 23 | ||| Fix-point data type for exotic recursion schemes of various kinds 24 | data Fix : (Type -> Type) -> Type where 25 | Fx : f (Fix f) -> Fix f 26 | 27 | ||| Nu fix-point functor for coinduction 28 | codata Nu : (f : Type -> Type) -> Type -> Type where 29 | NuF : ((a -> f a) -> a) -> b -> Nu f b 30 | 31 | ||| Mu fix-point functor for induction 32 | data Mu : (Type -> Type) -> Type where 33 | MuF : ({a : Type} -> (a -> f a) -> a) -> Mu f 34 | 35 | implementation Functor (Nu f) where 36 | map g (NuF h a) = NuF h (g a) 37 | 38 | implementation Base t (Nu f) where 39 | 40 | implementation Base (Fix t) f where 41 | 42 | implementation Base (Mu f) f where 43 | 44 | ||| Create a fix-point with a functor 45 | fix : f (Fix f) -> Fix f 46 | fix = Fx 47 | 48 | ||| Unfix a 'Fix f' 49 | unfix : Fix f -> f (Fix f) 50 | unfix (Fx x) = x 51 | 52 | data ListF : Type -> Type -> Type where 53 | NilF : ListF _ _ 54 | Cons : a -> b -> ListF a b 55 | 56 | data StreamF : Type -> Type -> Type where 57 | Pipe : a -> b -> StreamF a b 58 | 59 | implementation Functor (StreamF a) where 60 | map f (Pipe a b) = Pipe a (f b) 61 | 62 | implementation Functor (ListF a) where 63 | map _ NilF = NilF 64 | map f (Cons a b) = Cons a (f b) 65 | 66 | implementation Base b (ListF a) where 67 | 68 | implementation Base b (StreamF a) where 69 | 70 | ||| Lambek's lemma assures us this function always exists. 71 | lambek : (Recursive f t, Corecursive f t) => (t -> f t) 72 | lambek = cata (map embed) 73 | 74 | ||| The dual of Lambek's lemma. 75 | colambek : (Recursive f t, Corecursive f t) => (f t -> t) 76 | colambek = ana (map project) 77 | 78 | implementation Recursive (StreamF a) (Stream a) where 79 | project (x::xs) = Pipe x xs 80 | 81 | implementation Corecursive (StreamF a) (Stream a) where 82 | embed (Pipe x xs) = x::xs 83 | 84 | implementation Recursive (ListF a) (List a) where 85 | project [] = NilF 86 | project (x::xs) = Cons x xs 87 | 88 | implementation Corecursive (ListF a) (List a) where 89 | embed NilF = [] 90 | embed (Cons x xs) = x::xs 91 | -------------------------------------------------------------------------------- /Data/Functor/Foldable/Mod.idr: -------------------------------------------------------------------------------- 1 | ||| Module containing the main typeclasses and recursion schemes on them. 2 | module Data.Functor.Foldable.Mod 3 | 4 | import Control.Monad.Identity 5 | import Control.Monad.Free 6 | import Control.Comonad 7 | import Control.Comonad.Cofree 8 | 9 | %access public export 10 | 11 | ||| This is an interface which does nothing interesting, but it functions as a 12 | ||| way of saying "f is a base functor with underlying type t" 13 | interface Base t (f : Type -> Type) where 14 | 15 | ||| Interface for corecursive data types. Corecursive types correspond to 16 | ||| anamorphisms. 17 | interface (Functor f, Base t f) => Corecursive (f : Type -> Type) (t : Type) where 18 | embed : f t -> t 19 | 20 | ||| Recursive types correspond to catamorphisms. 21 | interface (Functor f, Base t f) => Recursive (f : Type -> Type) (t : Type) where 22 | project : t -> f t 23 | 24 | ||| Anamorphism, meant to build up a structure recursively. 25 | ana : (Corecursive f t) => (a -> f a) -> a -> t 26 | ana g = a' 27 | where a' x = embed . map a' . g $ x 28 | 29 | ||| Postpromorphism. Unfold a structure, applying a natural transformation along the way. 30 | postpro : (Recursive f t, Corecursive f t) => (f t -> f t) -> (a -> f a) -> a -> t 31 | postpro e g = a' 32 | where a' x = embed . map (ana (e . project) . a') . g $ x 33 | 34 | ||| Generalized Anamorphism 35 | ||| @ k A distributive law 36 | ||| @ g A (f . m)-coalgebra 37 | gana : (Corecursive f t, Monad m) => (k : {b : _} -> m (f b) -> f (m b)) -> (g : a -> f (m a)) -> a -> t 38 | gana k g = (gan k g) . pure . g 39 | where gan : (Corecursive f t, Monad m) => (k : {b : _} -> m (f b) -> f (m b)) -> (g : a -> f (m a)) -> m (f (m a)) -> t 40 | gan k g x = embed . map ((gan k g) . map g . join) . k $ x 41 | 42 | ||| Generalized catamorphism 43 | ||| @ k A distributive law 44 | ||| @ g A (f . w)-algebra 45 | gcata : (Recursive f t, Comonad w) => (k : {b:_} -> f (w b) -> w (f b)) -> (g : f (w a) -> a) -> t -> a 46 | gcata k g = g . extract . (gcat k g) 47 | where gcat : (Recursive f t, Comonad w) => (k : {b:_} -> f (w b) -> w (f b)) -> (g : f (w a) -> a) -> t -> w (f (w a)) 48 | gcat k g x = k . map (duplicate . map g . (gcat k g)) . project $ x 49 | 50 | ||| Generalized hylomorphism 51 | ||| @ k A distributive law on f 52 | ||| @ l A distributive law on l 53 | ||| @ f' A (f . w)-algebra 54 | ||| @ g' A (f . m)-coalgebra 55 | ghylo : (Functor f, Comonad w, Monad m) => 56 | (k : {b:_} -> f (w b) -> w (f b)) -> 57 | (l : {c:_} -> m (f c) -> f (m c)) -> 58 | (f' : f (w b) -> b) -> 59 | (g' : a -> f (m a)) -> 60 | a -> b 61 | ghylo k l f' g' = extract . (gh k l f' g') . pure where 62 | gh : (Functor f, Comonad w, Monad m) => (k : {d:_} -> f (w d) -> w (f d)) -> (l : {c:_} -> m (f c) -> f (m c)) -> (f' : f (w b) -> b) -> (g' : a -> f (m a)) -> m a -> w b 63 | gh k l f' g' x = map f' . k . map (duplicate . (gh k l f' g') . join) . l . map g' $ x 64 | 65 | ||| Distributive law for catamorphisms 66 | distCata : Functor f => f (Identity a) -> Identity (f a) 67 | distCata = Id . map runIdentity 68 | 69 | ||| Distributive law for anamorphisms. 70 | distAna : Functor f => Identity (f a) -> f (Identity a) 71 | distAna = map Id . runIdentity 72 | 73 | ||| Distributive law for futumorphisms. 74 | distFutu : (Functor f) => Free f (f a) -> f (Free f a) 75 | distFutu (Pure fa) = Pure <$> fa 76 | distFutu (Bind as) = Bind <$> (distFutu <$> as) 77 | 78 | ||| Futumorphism 79 | futu : (Corecursive f t) => (a -> f (Free f a)) -> a -> t 80 | futu = gana distFutu 81 | 82 | ||| Distributive law for histomorphisms 83 | distHisto : (Functor f) => f (Cofree f a) -> Cofree f (f a) 84 | distHisto = unfold g where 85 | g as = (extract <$> as, unwrap <$> as) 86 | 87 | ||| Histomorphism 88 | histo : (Recursive f t) => (f (Cofree f a) -> a) -> t -> a 89 | histo = gcata distHisto 90 | 91 | ||| Chronomorphism 92 | chrono : Functor f => (f (Cofree f b) -> b) -> (a -> f (Free f a)) -> a -> b 93 | chrono = ghylo distHisto distFutu 94 | 95 | ||| Catamorphism. Folds a structure. (see [here](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.41.125&rep=rep1&type=pdf)) 96 | cata : (Recursive f t) => (f a -> a) -> t -> a 97 | cata f = c 98 | where c x = f . map c . project $ x 99 | 100 | ||| Prepromorphism. Fold a structure while applying a natural transformation at each step. 101 | prepro : (Recursive f t, Corecursive f t) => (f t -> f t) -> (f a -> a) -> t -> a 102 | prepro e f = c 103 | where c x = f . map (c . (cata (embed . e))) . project $ x 104 | 105 | ||| Catamorphism interweaving two data types. 106 | dicata : (Recursive f b, Recursive f a) => (f (b, a) -> b) -> (f (b, a) -> a) -> b -> a 107 | dicata f g = snd . cata (\x => (f x, g x)) 108 | 109 | ||| Mutumorphism 110 | mutu : (Recursive f t) => (f (a, a) -> a) -> (f (a, a) -> a) -> t -> a 111 | mutu f g x = g . map (\x => (mutu g f x, mutu f g x)) . project $ x 112 | 113 | ||| Zygomorphism (see [here](http://www.iis.sinica.edu.tw/~scm/pub/mds.pdf) for a neat example) 114 | zygo : (Recursive f t) => (f b -> b) -> (f (b, a) -> a) -> t -> a 115 | zygo f g = snd . cata (\x => (f $ map fst x, g x)) 116 | 117 | ||| Paramorphism 118 | para : (Recursive f t, Corecursive f t) => (f (t, a) -> a) -> t -> a 119 | para f = snd . cata (\x => (embed $ map fst x, f x)) 120 | 121 | ||| Hylomorphism; equivalent to a catamorphism and an anamorphism taken together. 122 | hylo : Functor f => (f b -> b) -> (a -> f a) -> a -> b 123 | hylo f g = h 124 | where h x = f . map h . g $ x 125 | -------------------------------------------------------------------------------- /Justfile: -------------------------------------------------------------------------------- 1 | clean: 2 | sn c . 3 | rm -f tags 4 | 5 | build: 6 | idris --build recursion_schemes.ipkg 7 | 8 | test: 9 | idris --testpkg test.ipkg 10 | 11 | update-docs: 12 | sn c . 13 | rm -rf docs 14 | idris --mkdoc recursion_schemes.ipkg 15 | mv recursion_schemes_doc/ docs/ 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Vanessa McHale (c) 2017 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # recursion_schemes 2 | 3 | [](https://travis-ci.org/vmchale/recursion\_schemes) 4 | 5 | This is a library providing recursion schemes for Idris. It it is loosely based 6 | on Edward Kmett's [Haskell 7 | library](https://hackage.haskell.org/package/recursion-schemes). 8 | 9 | ## Installation 10 | 11 | First, install [idris-free](https://github.com/idris-hackers/idris-free), 12 | [comonad](https://github.com/vmchale/comonad) and [composition](https://github.com/vmchale/composition). Then: 13 | 14 | ``` 15 | idris --install recursion_schemes.ipkg 16 | ``` 17 | 18 | To run the tests, install [specdris](https://github.com/pheymann/specdris). 19 | Then: 20 | 21 | ``` 22 | idris --testpkg test.ipkg 23 | ``` 24 | 25 | ## Use 26 | 27 | The classic paper [Functional programming with bananas, lenses, envelopes and 28 | barbed wire](https://link.springer.com/chapter/10.1007/3540543961_7) is the 29 | inspiration behind the Haskell library and is the standard reference on the 30 | topic. You may also find [Law and Order in 31 | Algorithmics](https://pdfs.semanticscholar.org/7ca8/326eb63f32502c0fc2324b6217a7bc7e8af4.pdf) 32 | to be of use. 33 | 34 | ### Examples 35 | 36 | In the `Test.Spec` module there are several examples, including a catamorphism, 37 | a zygomorphism, a mutumorphism, an Elgot algebra, a paramorphism, a 38 | dynamorphism, and a hylomorphism. 39 | 40 | ### Documentation 41 | 42 | You can find documentation 43 | [here](https://vmchale.github.io/recursion_schemes/index.html). 44 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # morphisms 2 | - [x] catamorphism 3 | - [x] paramorphism 4 | - [x] futumorphism 5 | - [x] mutumorphism 6 | - [x] zygomorphism 7 | - [x] prepromorphism 8 | - [x] generalized anamorphism 9 | - [x] histomorphism 10 | - [x] dynamorphism 11 | - [x] chronomorphism 12 | - [ ] synchromorphism (see this paper: 13 | https://www.fernuni-hagen.de/imperia/md/content/fakultaetfuermathematikundinformatik/forschung/berichte/bericht_266.pdf) 14 | - [x] anamorphism 15 | - [x] apomorphism 16 | - [x] postpromorphism 17 | - [x] hylomorphism 18 | - [ ] monadic versions 19 | # nice stuff 20 | - [x] fancy type-level chicanery 21 | - [ ] Mu, Nu fix-point functors 22 | # tests 23 | - [x] zygomorphism 24 | - [x] elgot algebra 25 | - [x] Collatz sequence? 26 | - [x] hylomorphism 27 | - [x] catamorphism 28 | # proofs 29 | - [ ] cata/ana/hylo laws 30 | - [ ] termination proofs? 31 | # ci 32 | - [ ] make nix expression fetch/install dependencies? 33 | - [ ] script to bump dependencies to newest commit & attendant sha hash 34 | -------------------------------------------------------------------------------- /Test/Spec.idr: -------------------------------------------------------------------------------- 1 | module Test.Spec 2 | 3 | import Specdris.Spec 4 | import Data.Functor.Foldable 5 | import Data.Vect 6 | import Control.Comonad.Cofree 7 | 8 | -- FIXME morphisms with constraints? particularly re: symmteries 9 | -- "safe" compilation using this? 10 | -- particularly discrete pseudo-hamiltonian dynamics 11 | -- oh man finite symplectic geometry 12 | 13 | -- TODO computation of pi from http://www.cs.ox.ac.uk/jeremy.gibbons/publications/metamorphisms-mpc.pdf 14 | 15 | naturals : Nat -> ListF Nat Nat 16 | naturals Z = NilF 17 | naturals (S n) = Cons (n + 1) n 18 | 19 | -- This is also an instructive use of cofree comonads! 20 | -- Do note that it indexes starting at 0. 21 | catalan : Nat -> Nat 22 | catalan = dyna coalgebra naturals 23 | where 24 | coalgebra : ListF Nat (Cofree (ListF Nat) Nat) -> Nat 25 | coalgebra NilF = 1 26 | coalgebra (Cons n table) = sum (Prelude.List.zipWith (*) xs (reverse xs)) 27 | where 28 | xs = take n table 29 | take : Nat -> (Cofree (ListF Nat) Nat) -> List Nat 30 | take Z _ = [] 31 | take (S n) (Co a NilF) = [a] 32 | take (S n) (Co a (Cons v as)) = a :: take n as 33 | 34 | roundedSqrt : Nat -> Nat 35 | roundedSqrt = cast . cast {to=Integer} . sqrt . cast 36 | 37 | toN : Nat -> List Nat 38 | toN = reverse . ana naturals 39 | 40 | isPrime : Nat -> List Nat -> Bool 41 | isPrime n ns = all (\a => mod n a /= 0) (filter (<= (roundedSqrt n)) ns) 42 | 43 | dedup : (Eq a) => List a -> List a 44 | dedup = para pseudoalgebra where 45 | pseudoalgebra : (Eq a) => ListF a (List a, List a) -> List a 46 | pseudoalgebra NilF = [] 47 | pseudoalgebra (Cons x (past, xs)) = if elem x past then xs else x :: xs 48 | 49 | evenOdd : Nat -> Bool 50 | evenOdd = mutu odd even where 51 | odd : Maybe (Bool, Bool) -> Bool 52 | odd Nothing = False 53 | odd (Just (_, b)) = b 54 | even : Maybe (Bool, Bool) -> Bool 55 | even Nothing = True 56 | even (Just (_, b)) = b 57 | 58 | collatzCoalgebra : Int -> Either (List Int) (ListF Int Int) 59 | collatzCoalgebra 1 = Left [1] 60 | collatzCoalgebra 2 = Left [2, 1] 61 | collatzCoalgebra 3 = Left [3, 10, 5, 16, 8, 4, 2, 1] 62 | collatzCoalgebra 4 = Left [6, 3, 10, 5, 16, 8, 4, 2, 1] 63 | collatzCoalgebra n with (modInt n 2) 64 | | 0 = Right $ Cons n (divInt n 2) 65 | | _ = Right $ Cons n (3 * n + 1) 66 | 67 | collatz : Int -> List Int 68 | collatz = micro collatzCoalgebra 69 | 70 | elgotCoalgebra : List a -> Either (List (List a)) (ListF (List a) (List a)) 71 | elgotCoalgebra [] = Right NilF 72 | elgotCoalgebra (x :: []) = Left ([[x]]) 73 | elgotCoalgebra (x :: xs) = Right (Cons (x :: xs) xs) 74 | 75 | -- fibonacci zygomorphism? 76 | 77 | zygoPseudoalgebra : ListF Int (Bool, Int) -> Int 78 | zygoPseudoalgebra NilF = 0 79 | zygoPseudoalgebra (Cons n (b, x)) = if b then (n+x) else (n-x) 80 | 81 | zygoAlgebra : ListF Int Bool -> Bool 82 | zygoAlgebra NilF = False 83 | zygoAlgebra (Cons _ bool) = not bool 84 | 85 | plusMinus : List Int -> Int 86 | plusMinus = zygo zygoAlgebra zygoPseudoalgebra 87 | 88 | algebra' : ListF (List a) (List a) -> List a 89 | algebra' NilF = [] 90 | algebra' (Cons x xs) = x ++ xs 91 | 92 | cataConcat : List (List a) -> List a 93 | cataConcat = cata algebra' 94 | 95 | algebra : ListF (List a) (List (List a)) -> List (List a) 96 | algebra NilF = [] 97 | algebra (Cons x xs) = x::xs 98 | 99 | coalgebra : List a -> ListF (List a) (List a) 100 | coalgebra (x::xs) = Cons (x::xs) xs 101 | coalgebra [] = NilF 102 | 103 | suffix : List a -> List (List a) 104 | suffix = hylo algebra coalgebra . drop 1 105 | 106 | export 107 | specSuite : IO () 108 | specSuite = 109 | spec $ do 110 | describe "hylo" $ 111 | it "should be able to implement the suffix function" $ 112 | (suffix . unpack) "ego" `shouldBe` [['g','o'], ['o']] 113 | describe "cata" $ 114 | it "should be able to implement 'concat'" $ 115 | (cataConcat . map unpack) [ "I", "am" ] `shouldBe` ['I', 'a', 'm'] 116 | describe "zygo" $ 117 | it "should be able to implement plusMinus" $ 118 | plusMinus [1,2,3] `shouldBe` -4 119 | describe "micro" $ 120 | it "should provide a simple way to compute the Collatz sequence associated with a number" $ 121 | collatz 12 `shouldBe` [12, 6, 3, 10, 5, 16, 8, 4, 2, 1] 122 | describe "mutu" $ 123 | it "should be able to do recursion on the natural numbers to check for parity" $ 124 | (evenOdd . fromIntegerNat) 10 `shouldBe` True 125 | describe "para" $ 126 | it "should provide an elegant way to remove duplicates from a list when order doesn't matter" $ 127 | dedup [1,1,2,3,4,5,4] `shouldBe` [1,2,3,5,4] 128 | describe "dyna" $ 129 | it "should do something with catalan numbers" $ 130 | catalan 6 `shouldBe` 132 131 | describe "ana" $ 132 | it "should give the first n naturals" $ 133 | toN 5 `shouldBe` [1,2,3,4,5] 134 | -------------------------------------------------------------------------------- /docs/IdrisDoc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmchale/recursion_schemes/e10780a16028a6f8fe418d8251578a7d1c43ebe8/docs/IdrisDoc -------------------------------------------------------------------------------- /docs/docs/Control.Comonad.html: -------------------------------------------------------------------------------- 1 | 2 |
Module providing comonads for idris.
3 |Lift a function into a function on comonadic values.
8 |A comonad is the categorical dual of a monad. It must satisfy the following
13 | laws:
extend extract = id
15 | extract . extend f = f
16 | extend f . extend g = extend (f . extend g)
17 |
18 | CoApplicatives provide a categorical approach to zippers. They must satisfy
23 | the following laws:
(.) <$> u <@> v <@> w = u <@> (v <@> w)
25 | extract (p <@> q) = extract p (extract q)
26 | duplicate (p <@> q) = (<@>) <$> duplicate p <@> duplicate q
27 |
28 | If 'w' is an applicative functor, it must further satisfy
29 |(<@>) = (<*>)
30 |
31 | Dual to '>>='
46 |Left-to-right cokliesli composition
53 |Right-to-left cokliesli composition
60 |Operator giving us 'extend'
65 |Anamorphism that allows shortcuts.
10 |Mendler's histomorphism
18 |Gibbons' metamorphism. Tear down a structure, transform it, and then build up a new structure
31 |Mendler's catamorphism
37 |Erwig's metamorphism. Essentially a hylomorphism with a natural
47 | transformation in between. This allows us to use more than one functor in a
48 | hylomorphism.
Elgot algebra (see this paper)
57 |A dynamorphism builds up with an anamorphism and tears down with a
68 | histomorphism. Useful for lexical scoping.
A dynamorphism without a natural transformation in between.
77 |Elgot coalgebra
85 |Unfix a 'Fix f'
4 |Lambek's lemma assures us this function always exists.
10 |Create a fix-point with a functor
12 |The dual of Lambek's lemma.
18 |Nu fix-point functor for coinduction
27 |Mu fix-point functor for induction
35 |Fix-point data type for exotic recursion schemes of various kinds
47 |Cofree comonads; useful for histomorphisms and also recursion
3 |Recursion using comonads
10 |Typeclass for cofree comonads
11 |Constructor for a cofree comonad
18 |The negation of equality is symmetric (follows from symmetry of equality)
12 |Everything is decidably equal to itself
77 |Decision procedures for propositional equality
80 |A family describing which types are available in the FFI
6 |The type used to specify the names of foreign functions in this FFI
9 |How this FFI describes exported datatypes
12 |A family describing which types are available in the FFI
15 |The type used to specify the names of foreign functions in this FFI
17 |How this FFI describes exported datatypes
19 |A descriptor for the C FFI. See the constructors of C_Types
5 | and C_IntTypes
for the concrete types that are available.
Supported C foreign types
8 |Supported C integer types
12 |Sets equipped with a single binary operation that is associative. Must
3 | satisfy the following laws:
<+>
:Sets equipped with a single binary operation that is associative, along with
12 | a neutral element for that binary operation. Must satisfy the following
13 | laws:
<+>
:<+>
:Manually assign a type to an expression.
5 |the type to assign
6 |the element to get the type
7 |Return the second element of a pair.
10 |Identity function.
12 |Return the first element of a pair.
15 |Takes in the first two arguments in reverse order.
21 |the function to flip
22 |Constant function. Ignores its second argument.
25 |Equality is a congruence.
29 |Function application.
33 |Decidability. A decidable property either holds or is a contradiction.
36 |Function composition
49 |Boolean OR only evaluates the second argument if the first is False
.
Boolean NOT
7 |The underlying implementation of the if ... then ... else ... syntax
11 |the condition on the if
12 |the value if b is true
13 |the falue if b is false
14 |Boolean Data Type
15 |Boolean AND only evaluates the second argument if the first is True
.
Keep the payloads of all Right constructors in a list of Eithers
5 |Right is injective
9 |Split a list of Eithers into a list of the left elements and a list of the right elements
13 |Right becomes left and left becomes right
17 |Convert a Maybe to an Either by using a default value in case of Nothing
21 |the default value
22 |Keep the payloads of all Left constructors in a list of Eithers
25 |Left is injective
29 |True if the argument is Right, False otherwise
32 |True if the argument is Left, False otherwise
35 |Remove a "useless" Either by collapsing the case distinction
38 |Simply-typed eliminator for Either
45 |the action to take on Left
46 |the action to take on Right
47 |the sum to analyze
48 |A sum type
51 |Write a string to a file
6 |Check whether a file handle is actually a null pointer
8 |Standard output
9 |Standard input
10 |Standard output
11 |Read the contents of a text file into a string
14 | This checks the size of the file before beginning to read, and only
15 | reads that many bytes, to ensure that it remains a total function if
16 | the file is appended to while being read.
17 | This only works reliably with text files, since it relies on null-terminated
18 | strings internally.
19 | Returns an error if filepath is not a normal file.
Open a file using C11 extended modes.
28 |the filename
29 |the mode; either Read, WriteTruncate, Append, ReadWrite, ReadWriteTruncate, or ReadAppend
30 |Open a file
34 |the filename
35 |the mode; either Read, WriteTruncate, Append, ReadWrite, ReadWriteTruncate, or ReadAppend
36 |Open a file
42 |the filename
43 |the mode as a String ("r"
, "w"
, or "r+"
)
Return the size of a File
49 | Returns an error if the File is not an ordinary file (e.g. a directory)
50 | Also note that this currently returns an Int, which may overflow if the
51 | file is very big
Write a line to a file
67 |a file handle which must be open for writing
68 |the line to write to the file
69 |Read a line from a file
72 |a file handle which must be open for reading
73 |Read up to a number of characters from a file
77 |a file handle which must be open for reading
78 |Check if a file handle has reached the end
80 |Modes for opening files
91 |An error from a file operation
92 |A file handle
94 |A directory handle
96 |Add together all the elements of a structure
6 |Multiply together all elements of a structure
10 |The disjunction of all elements of a structure containing
13 | lazy boolean values. or
short-circuits from left to right, evaluating
14 | either until an element is True
or no elements remain.
Combine into a monoid the collective results of applying a function
27 | to each element of a structure
Combine each element of a structure into a monoid
32 |The disjunction of the collective results of applying a
37 | predicate to all elements of a structure. any
short-circuits
38 | from left to right.
The conjunction of all elements of a structure containing
42 | lazy boolean values. and
short-circuits from left to right,
43 | evaluating until either an element is False
or no elements remain.
The disjunction of the collective results of applying a
49 | predicate to all elements of a structure. all
short-circuits
50 | from left to right.
The Foldable
interface describes how you can iterate over the
52 | elements in a parameterised type and combine the elements
53 | together, using a provided function, into a single result.
Successively combine the elements in a parameterised type using
61 | the provided function, starting with the element that is in the
62 | final position i.e. the right-most position.
The same as foldr
but begins the folding from the element at
70 | the initial position in the data structure i.e. the left-most
71 | position.
Run something for effects, throwing away the return value
5 |Functors allow a uniform action over a parameterised type.
6 |Apply a function across everything of type 'a' in a
11 | parameterised type
An infix alias for map
, applying a function across everything of
17 | type 'a' in a parameterised type
the parameterised type
19 |the function to apply
20 |Returns Just
the given value if the conditional is True
5 | and Nothing
if the conditional is False
.
Returns Nothing
when applied to neutral
, and Just
the value otherwise.
Convert a Maybe a
value to an a
value, using neutral
in the case
20 | that the Maybe
value is Nothing
.
Decide whether a 'Maybe' is 'Just'
28 |Convert a Maybe a
value to an a
value by providing a default a
value
31 | in the case that the Maybe
value is Nothing
.
Transform any semigroup into a monoid by using Nothing
as the
34 | designated neutral element and collecting the contents of the
35 | Just
constructors using a semigroup structure on a
. This is
36 | the behaviour in the Haskell libraries.
An optional value. This can be used to represent the possibility of
39 | failure, where a function may return a value, or not.
Proof that some Maybe
is actually Just
Monads and Functors
3 |For compatibility with Haskell. Note that monads are not free to
6 | define return
and pure
differently!
Similar to foldl
, but uses a function wrapping its result in a Monad
.
15 | Consequently, the final value is wrapped in the same Monad
.
Surround a String
with parentheses depending on a condition.
whether to add parentheses
6 |A helper for the common case of showing a non-infix constructor with at
14 | least one argument, for use with showArg
.
Apply showCon
to the precedence context, the constructor name, and the
16 | args shown with showArg
and concatenated. Example:
data Ann a = MkAnn String a
18 |
19 | Show a => Show (Ann a) where
20 | showPrec d (MkAnn s x) = showCon d "MkAnn" $ showArg s ++ showArg x
21 |
22 | A helper for the common case of showing a non-infix constructor with at
25 | least one argument, for use with showCon
.
This adds a space to the front so the results can be directly
27 | concatenated. See showCon
for details and an example.
Gives the constructor index of the Prec as a helper for writing implementations.
38 |Things that have a canonical String
representation.
Convert a value to its String
representation.
Convert a value to its String
representation in a certain precedence
54 | context.
A value should produce parentheses around itself if and only if the given
56 | precedence context is greater than or equal to the precedence of the
57 | outermost operation represented in the produced String
. This is
58 | different from Haskell, which requires it to be strictly greater. Open
59 | should thus always produce no outermost parens, App
should always
60 | produce outermost parens except on atomic values and those that provide
61 | their own bracketing, like Pair
and List
.
The precedence of an Idris operator or syntactic context.
63 |Combine three streams by applying a function element-wise along them
10 |Combine two streams element-wise using a function.
16 |the function to combine elements with
17 |the first stream of elements
18 |the second stream of elements
19 |Combine three streams into a stream of tuples elementwise
25 |Create a stream of pairs from two streams
29 |Split a stream of three-element tuples into three streams
35 |Create a pair of streams from a stream of pairs
39 |Take precisely n elements from the stream
42 |how many elements to take
43 |the stream
44 |All but the first element
46 |Produce a Stream of left folds of prefixes of the given Stream
52 |the combining function
53 |the initial value
54 |the Stream to process
55 |An infinite stream of repetitions of the same thing
57 |Generate an infinite stream by repeatedly applying a function
61 |the function to iterate
62 |the initial value that will be the head of the stream
63 |Get the nth element of a stream
66 |The first element of an infinite stream
68 |Drop the first n elements from the stream
71 |how many elements to drop
72 |Return the diagonal elements of a stream of streams
74 |Produce a Stream repeating a sequence
77 |the sequence to repeat
78 |proof that the list is non-empty
79 |An infinite stream
81 |