free-functors-1.0: src/Data/Functor/Free.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE
TypeFamilies
, TypeOperators
, DeriveFunctor
, DeriveFoldable
, ConstraintKinds
, TemplateHaskell
, DeriveTraversable
, FlexibleInstances
, UndecidableInstances
, QuantifiedConstraints
, MultiParamTypeClasses
#-}
-----------------------------------------------------------------------------
-- |
-- Module : Data.Functor.Free
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : sjoerd@w3future.com
-- Stability : experimental
-- Portability : non-portable
--
-- A free functor is left adjoint to a forgetful functor.
-- In this package the forgetful functor forgets class constraints.
-----------------------------------------------------------------------------
module Data.Functor.Free (
Free(..)
, deriveInstances
, unit
, rightAdjunct
, counit
, leftAdjunct
, transform
, unfold
, convert
, convertClosed
, Extract(..)
, Duplicate(..)
-- * Coproducts
, Coproduct
, coproduct
, inL
, inR
, InitialObject
, initial
-- * Internal
, ShowHelper(..)
) where
import Data.Function
import Data.Void
import Data.Functor.Free.Internal
-- | @unfold f = coproduct (unfold f) unit . f@
--
-- `inL` and `inR` are useful here. For example, the following creates the list @[1..10]@ as a @Free Monoid@:
--
-- @unfold (\b -> if b == 0 then mempty else `inL` (b - 1) \<> `inR` b) 10@
unfold :: (b -> Coproduct c b a) -> b -> Free c a
unfold f = fix $ \go -> transform (\k -> either (rightAdjunct k . go) k) . f
-- | @convert = rightAdjunct pure@
convert :: (c (f a), Applicative f) => Free c a -> f a
convert = rightAdjunct pure
-- | @convertClosed = rightAdjunct absurd@
convertClosed :: c r => Free c Void -> r
convertClosed = rightAdjunct absurd
-- | Products of @Monoid@s are @Monoid@s themselves. But coproducts of @Monoid@s are not.
-- However, the free @Monoid@ applied to the coproduct /is/ a @Monoid@, and it is the coproduct in the category of @Monoid@s.
-- This is also called the free product, and generalizes to any algebraic class.
type Coproduct c m n = Free c (Either m n)
coproduct :: c r => (m -> r) -> (n -> r) -> Coproduct c m n -> r
coproduct m n = rightAdjunct (either m n)
inL :: m -> Coproduct c m n
inL = unit . Left
inR :: n -> Coproduct c m n
inR = unit . Right
type InitialObject c = Free c Void
initial :: c r => InitialObject c -> r
initial = rightAdjunct absurd
deriveInstances ''Num
deriveInstances ''Fractional
deriveInstances ''Floating
deriveInstances ''Semigroup
deriveInstances ''Monoid