File: Logistic.hs

package info (click to toggle)
haskell-data-functor-logistic 0.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 72 kB
  • sloc: haskell: 64; makefile: 2
file content (80 lines) | stat: -rw-r--r-- 2,567 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Data.Functor.Logistic
  ( Logistic(..)
  , setters
  ) where

import Data.Distributive
import Data.Functor.Identity
import Data.Functor.Contravariant
import Data.Functor.Compose
import Data.Functor.Product
import Data.Proxy
import Data.Complex
import GHC.Generics

class Functor t => Logistic t where
  deliver :: Contravariant f => f (t a -> t a) -> t (f (a -> a))
  default deliver :: (Generic1 t, Logistic (Rep1 t), Contravariant f) => f (t a -> t a) -> t (f (a -> a))
  deliver f = to1 $ deliver $ contramap (\g -> to1 . g . from1) f

instance Logistic Identity where
  deliver f = Identity (contramap fmap f)

instance Logistic Par1 where
  deliver f = Par1 (contramap fmap f)

instance Logistic f => Logistic (M1 i c f) where
  deliver f = M1 $ deliver $ contramap (\g -> M1 . g . unM1) f

instance Logistic f => Logistic (Rec1 f) where
  deliver f = Rec1 $ deliver $ contramap (\g -> Rec1 . g . unRec1) f

instance Logistic Proxy where
  deliver _ = Proxy

instance Logistic U1 where
  deliver _ = U1

-- | Update only if the argument matches
instance Eq r => Logistic ((->) r) where
  deliver f x = contramap (\u g r -> if r == x then u (g r) else g r) f

instance (Logistic f, Logistic g) => Logistic (Product f g) where
  deliver f = Pair
    (deliver (contramap (\u (Pair a b) -> Pair (u a) b) f))
    (deliver (contramap (\u (Pair a b) -> Pair a (u b)) f))

instance (Logistic f, Logistic g) => Logistic (f :*: g) where
  deliver f
    = deliver (contramap (\u (a :*: b) -> u a :*: b) f)
    :*: deliver (contramap (\u (a :*: b) -> a :*: u b) f)

instance (Logistic f, Logistic g, Applicative f, Traversable g, Distributive g) => Logistic (Compose f g) where
  deliver f = Compose
    $ fmap getCompose
    $ deliver
    $ Compose
    $ deliver
    $ contramap go f
    where
      go p = Compose . sequenceA . p . distribute . getCompose

instance (Logistic f, Logistic g, Applicative f, Traversable g, Distributive g) => Logistic (f :.: g) where
  deliver f = Comp1 $ fmap unComp1 $ deliver $ Comp1 $ deliver $ contramap go f
    where
      go p = Comp1 . sequenceA . p . distribute . unComp1

instance Logistic Complex where
  deliver f
    = contramap (\g (a :+ b) -> g a :+ b) f
    :+ contramap (\g (a :+ b) -> a :+ g b) f

setters :: Logistic t => t ((a -> a) -> t a -> t a)
setters = getOp <$> deliver (Op id)
{-# INLINE setters #-}