/ src / Hyper.hs
Hyper.hs
  1  {-# LANGUAGE FlexibleContexts #-}
  2  {-# LANGUAGE FlexibleInstances #-}
  3  {-# LANGUAGE LambdaCase #-}
  4  {-# LANGUAGE PostfixOperators #-}
  5  {-# LANGUAGE RankNTypes #-}
  6  {-# LANGUAGE ScopedTypeVariables #-}
  7  {-# LANGUAGE TypeFamilies #-}
  8  {-# LANGUAGE TypeOperators #-}
  9  {-# HLINT ignore "Use camelCase" #-}
 10  {-# LANGUAGE UndecidableInstances #-}
 11  {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
 12  
 13  module Hyper where
 14  
 15  import Control.Monad (forever)
 16  import Control.Monad.Cont (ContT, MonadCont (callCC))
 17  import Control.Monad.Trans (MonadIO, MonadTrans, liftIO)
 18  import Control.Monad.Writer (MonadWriter (..), Writer, lift)
 19  import Data.Kind (Type)
 20  import Data.Semilattice.Join (Join, (\/))
 21  import Data.Semilattice.Lower (Lower, lowerBound)
 22  import Data.Void (Void, absurd)
 23  import Debug.Trace (trace)
 24  import Numeric.Natural (Natural)
 25  import Prelude hiding ((||))
 26  
 27  -- hyperfunction
 28  newtype a :-> b = Hyper {hyp :: (b :-> a) -> b}
 29  
 30  infixr 0 :->
 31  
 32  konst :: b -> (a :-> b)
 33  konst x = Hyper $ const x
 34  
 35  -- natural numbers as a data type
 36  data N = Z | S N
 37  
 38  fold :: N -> (a -> a) -> a -> a
 39  fold Z _ z = z
 40  fold (S n) s z = s (fold n s z)
 41  
 42  -- church encoding of natural numbers
 43  newtype NC = NC {nat :: forall r. (r -> r) -> r -> r}
 44  
 45  instance Show NC where
 46    show (NC n) = show $ n (+ 1) 0
 47  
 48  church :: N -> NC
 49  church n = NC $ \s z -> fold n s z
 50  
 51  nat' :: Natural -> N
 52  nat' 0 = Z
 53  nat' n = S $ nat' (n - 1)
 54  
 55  church' :: Natural -> NC
 56  church' = church . nat'
 57  
 58  -- standard recursive definition of less than or equal
 59  lte :: N -> N -> Bool
 60  lte Z _ = True
 61  lte (S _) Z = False
 62  lte (S n) (S m) = lte n m
 63  
 64  -- less than or equal using hyperfunctions and church numerals
 65  (<=?) :: NC -> NC -> Bool
 66  n <=? m =
 67    hyp (nat n ns nz) (nat m ms mz)
 68    where
 69      ns :: (Bool :-> Bool) -> Bool :-> Bool
 70      ns mk = Hyper $ \nk -> hyp nk mk
 71  
 72      ms :: (Bool :-> Bool) -> Bool :-> Bool
 73      ms nk = Hyper $ \mk -> hyp mk nk
 74  
 75      nz :: Bool :-> Bool
 76      nz = konst True
 77  
 78      mz :: Bool :-> Bool
 79      mz = konst False
 80  
 81  -- substraction
 82  
 83  rep :: (a -> b) -> (a :-> b)
 84  rep f = f <| rep f
 85  
 86  -- "stream" of functions constructora
 87  (<|) :: (a -> b) -> (a :-> b) -> (a :-> b)
 88  f <| h = Hyper $ \k -> f (hyp k h)
 89  
 90  -- zip together two streams of functions (represented as hyperfunctions)
 91  (<.>) :: (b :-> c) -> (a :-> b) -> (a :-> c)
 92  f <.> g = Hyper $ \h -> hyp f (g <.> h)
 93  
 94  -- "fold" a stream of functions to a value
 95  run :: (a :-> a) -> a
 96  run h = hyp h (Hyper run)
 97  
 98  -- | Subtraction of church numerals using hyperfunctions
 99  --
100  -- * zip together two streams of functions representing the two numbers to be subtracted
101  -- * the first (finite) part of the stream consists in n (Resp. m) applications of the identity function
102  -- * the second (infinite) part of the stream consists in either constant zero (for n) or constant successor (for m)
103  -- * hence zipping the two streams results in a stream of functions that first apply identity min(n,m) times
104  --   and then apply either constant zero (if n <= m) or constant successor (if n > m)
105  (-|) :: NC -> NC -> NC
106  n -| m =
107    NC $
108      \s z ->
109        run
110          ( nat n ids (rep (const z))
111              <.> nat m ids (rep s)
112          )
113    where
114      ids = (id <|)
115  
116  -- * Basic Message passing
117  
118  type Consumer input r = r :-> (input -> r)
119  
120  cons :: (input -> r -> r) -> Consumer input r -> Consumer input r
121  cons f c = Hyper $ \q i -> f i (hyp q c)
122  
123  type Producer output r = (output -> r) :-> r
124  
125  prod :: output -> Producer output r -> Producer output r
126  prod o p = Hyper $ \q -> hyp q p o
127  
128  exec :: Producer output r -> Consumer output r -> r
129  exec = hyp
130  
131  -- same logic as `(<=?)` but for zipping two lists: it alternates
132  -- between the two lists until it reaches the end of either one then
133  -- constantly returns the empty list
134  zip :: forall a b. [a] -> [b] -> [(a, b)]
135  zip xs ys = exec (foldr xf xb xs) (foldr yf yb ys)
136    where
137      xf :: a -> Producer a [(a, b)] -> Producer a [(a, b)]
138      xf = prod
139  
140      xb = konst []
141  
142      yf :: b -> Consumer a [(a, b)] -> Consumer a [(a, b)]
143      yf y = cons (\x pairs -> (x, y) : pairs)
144  
145      yb :: Consumer a [(a, b)]
146      yb = konst (const [])
147  
148  -- * CCS
149  
150  data Act n = Tau | Rcv n | Snd n
151    deriving (Eq, Show)
152  
153  infixr 8 :·
154  
155  data P n
156    = (:·) (Act n) (P n) -- sequence
157    | End -- termination
158    | (:+) (P n) (P n) -- non deterministic choice
159    | (:|) (P n) (P n) -- parallel
160    | New n (P n) -- name restriction
161    | Rep (P n) -- duplication
162    deriving (Eq, Show)
163  
164  -- An algebra to capture denotational semantics of CCS expressions of type `P n`
165  class CCSAlg c where
166    -- | The type of names of this interpretation
167    type Name c :: Type
168  
169    -- | interpret sequences
170    (·) :: Act (Name c) -> c -> c
171  
172    -- | interpret termination
173    end :: c
174  
175    -- | interpret non-determinism
176    (⊕) :: c -> c -> c
177  
178    -- | interpret parallelism
179    (||) :: c -> c -> c
180  
181    -- | Interpret name restriction
182    new :: Name c -> c -> c
183  
184    -- | Repetition
185    (!) :: c -> c
186  
187  interpret :: (CCSAlg c) => P (Name c) -> c
188  interpret = \case
189    a :· p -> a · interpret p
190    End -> end
191    p :+ q -> interpret p ⊕ interpret q
192    p :| q -> interpret p || interpret q
193    New n p -> new n (interpret p)
194    Rep p -> (interpret p !)
195  
196  -- Hyperfunctions model of CCS
197  
198  type Communicator n r = (Message n -> r) :-> (Message n -> r)
199  
200  data Message n = Q | A (Act n)
201  
202  interp :: (CCSAlg r, n ~ Name r) => Communicator n r -> r
203  interp p = hyp p one Q
204  
205  one :: (CCSAlg r, n ~ Name r) => Communicator n r
206  one = Hyper $ \p -> \case
207    A a -> a · interp p
208    Q -> end
209  
210  instance (Eq n, Join r, Lower r) => CCSAlg (Communicator n r) where
211    type Name (Communicator n r) = n
212    a · p =
213      Hyper $ \q m ->
214        case (a, m) of
215          (_, Q) -> hyp q p (A a)
216          (Snd n, A (Rcv n')) | n == n' -> hyp q p (A Tau)
217          _ -> lowerBound -- FIXME: should be the bottom of a semilattice?
218    end = konst lowerBound
219    p ⊕ q = Hyper $ \r m -> hyp p r m \/ hyp q r m
220    p || q = par p q ⊕ par q p
221    new n p =
222      Hyper $ \q -> \case
223        A Rcv {} -> lowerBound
224        A Snd {} -> lowerBound
225        m -> hyp p (new n q) m
226    (!) p = p `par` (p !)
227  
228  par :: (CCSAlg (b :-> a)) => (a :-> b) -> (b :-> a) -> a :-> b
229  par p q = Hyper $ \r -> hyp p (q || r)
230  
231  -- denotational model representing processes as rose trees where nodes
232  -- are actions
233  newtype Proc n = Proc {root :: [(Act n, Proc n)]}
234    deriving (Show)
235  
236  instance (Eq n) => Join (Proc n) where
237    (\/) = (⊕)
238  
239  instance Lower (Proc n) where
240    lowerBound = Proc []
241  
242  interp' :: (CCSAlg c) => Proc (Name c) -> c
243  interp' (Proc []) = end
244  interp' (Proc ((a, p) : q)) = a · interp' p ⊕ interp' (Proc q)
245  
246  instance (Eq n) => CCSAlg (Proc n) where
247    type Name (Proc n) = n
248  
249    a · p = Proc [(a, p)]
250    end = Proc []
251    p ⊕ q = Proc (root p <> root q)
252    p || q = par' p q ⊕ par' q p
253    new n p =
254      Proc
255        [ (a, new n p')
256          | (a, p') <- root p,
257            a /= Rcv n,
258            a /= Snd n
259        ]
260    (!) p = step (p ⊕ sync p p) (p !)
261  
262  par' :: (Eq n) => Proc n -> Proc n -> Proc n
263  par' p q = sync p q ⊕ step p q
264  
265  step :: (Eq n) => Proc n -> Proc n -> Proc n
266  step p q = Proc [(a, p' || q) | (a, p') <- root p]
267  
268  sync :: (Eq n) => Proc n -> Proc n -> Proc n
269  sync p q =
270    Proc [(Tau, p' || q') | (Rcv n, p') <- root p, (Snd n', q') <- root q, n == n']
271  
272  pr :: P String
273  pr = (Rcv "a" :· Rcv "b" :· End) :| (Snd "a" :· End)
274  
275  -- interpret pr :: Proc String
276  it :: Proc String
277  it =
278    Proc
279      { root =
280          [ (Tau, Proc {root = [(Rcv "b", Proc {root = []})]}),
281            ( Rcv "a",
282              Proc
283                { root =
284                    [ (Rcv "b", Proc {root = [(Snd "a", Proc {root = []})]}),
285                      (Snd "a", Proc {root = [(Rcv "b", Proc {root = []})]})
286                    ]
287                }
288            ),
289            ( Snd "a",
290              Proc
291                { root =
292                    [ (Rcv "a", Proc {root = [(Rcv "b", Proc {root = []})]})
293                    ]
294                }
295            )
296          ]
297      }
298  
299  -- * LogicT monda
300  
301  -- hyperfunction based interleaving of two lists
302  interleave :: [a] -> [a] -> [a]
303  interleave xs ys = hyp xz yz
304    where
305      xz = foldr (\x xk -> (x :) <| xk) (Hyper (const [])) xs
306      yz = foldr (\y yk -> (y :) <| yk) (Hyper (const [])) ys
307  
308  -- LogicT is a CPS-encoded list transformer
309  -- first arg is cons, second arg is nil
310  newtype LogicT m a = LogicT {runLogicT :: forall b. (a -> m b -> m b) -> m b -> m b}
311  
312  evalLogicT :: (Applicative m) => LogicT m a -> m [a]
313  evalLogicT ls = runLogicT ls (\c -> fmap (c :)) (pure [])
314  
315  (<<|) :: (Monad m) => (m b -> a) -> m (m b :-> a) -> m b :-> a
316  f <<| h = Hyper $ \k -> f (h >>= hyp k)
317  
318  -- * Continuation based concurrency
319  
320  newtype Cont r a = Cont {runCont :: (a -> r) -> r}
321  
322  instance Functor (Cont r) where
323    f `fmap` (Cont k) = Cont $ \g -> k (g . f)
324  
325  instance Applicative (Cont r) where
326    pure a = Cont $ \k -> k a
327    Cont f <*> Cont a = Cont $ \k -> f (\g -> a (k . g))
328  
329  instance Monad (Cont r) where
330    return = pure
331    Cont m >>= f = Cont $ \k ->
332      m
333        ( \a -> case f a of
334            Cont g -> g k
335        )
336  
337  instance MonadCont (Cont r) where
338    callCC f = Cont $ \k -> runCont (f $ \x -> Cont $ \_ -> k x) k
339  
340  data Action m = Atom (m (Action m)) | Fork (Action m) (Action m) | Stop
341  
342  type C m = Cont (Action m)
343  
344  atom :: (Functor m) => m a -> C m a
345  atom m = Cont $ \k -> Atom (k <$> m)
346  
347  fork :: (Monad m) => C m a -> C m ()
348  fork m = Cont $ \k -> Fork (action m) (k ())
349  
350  action :: (Monad m) => C m a -> Action m
351  action (Cont f) = Atom $ return $ f (const Stop)
352  
353  prog :: C (Writer String) ()
354  prog = do
355    atom (tell "go!")
356    fork (forever $ atom (tell "to"))
357    forever $ atom (tell "fro")
358  
359  -- round-robin scheduling of Actions
360  roundC :: (Monad m) => [Action m] -> m ()
361  roundC = \case
362    [] -> return ()
363    (a : as) -> case a of
364      Atom ma -> ma >>= \b -> roundC (as <> [b])
365      Fork b b' -> roundC (as <> [b, b'])
366      Stop -> roundC as
367  
368  runC :: (Monad m) => C m a -> m ()
369  runC p = roundC [action p]
370  
371  prog' :: C IO ()
372  prog' = do
373    atom $ putStrLn "foo"
374    fork (forever $ atom (putStrLn "to"))
375    forever $ atom (putStrLn "fro")
376  
377  -- * Concurrency monad based on hyperfunctions
378  
379  type Conc r m = Cont (m r :-> m r)
380  
381  atom_h :: (Monad m) => m a -> Conc r m a
382  atom_h a = Cont $ \k -> id <<| (k <$> a)
383  
384  fork_h :: forall r m a. Conc r m a -> Conc r m ()
385  fork_h m = Cont $ \k ->
386    let k' = k ()
387        m' = runCont m
388     in m' $ const k'
389  
390  run_h :: (Monad m) => Conc r m a -> m r
391  run_h c = run (runCont c (\_ -> rep id))
392  
393  prog'' :: Conc r IO b
394  prog'' = do
395    atom_h $ putStrLn "foo"
396    fork_h (forever $ atom_h (putStrLn "to"))
397    forever $ atom_h (putStrLn "fro")
398  
399  -- * Pipes
400  
401  -- similar to Gonzales' `pipes` library
402  newtype Pipe r i o m a = MkPipe {unPipe :: (a -> Result (m r) i o) -> Result (m r) i o}
403  
404  type Result r i o = Producer i r -> Consumer o r -> r
405  
406  instance Functor (Pipe r i o m) where
407    f `fmap` (MkPipe k) = MkPipe $ \g -> k (g . f)
408  
409  instance Applicative (Pipe r i o m) where
410    pure a = MkPipe $ \k -> k a
411    MkPipe f <*> MkPipe a = MkPipe $ \k -> f (\g -> a (k . g))
412  
413  instance Monad (Pipe r i o m) where
414    return = pure
415    MkPipe m >>= f = MkPipe $ \k ->
416      m
417        ( \a -> case f a of
418            MkPipe g -> g k
419        )
420  
421  instance MonadTrans (Pipe r i o) where
422    lift m = MkPipe $ \k p c -> m >>= \m' -> k m' p c
423  
424  -- producer side of a pipe, producing a value of type o
425  yield :: o -> Pipe r i o m ()
426  yield o = MkPipe $ \k p c -> hyp c (Hyper (k () p)) o
427  
428  -- consumer side of a pipe, awaiting a value of type `i` from a symmetric `yield`
429  await :: Pipe r i o m i
430  await = MkPipe $ \k p c -> hyp p (Hyper (\p' x -> k x p' c))
431  
432  -- terminates a pipe, returning some action producing a result of type `r`
433  halt :: m r -> Pipe r i o m x
434  halt x = MkPipe $ \_ _ _ -> x
435  
436  -- "merges" 2 compatible pipes, a consumer side and a producer side, yielding
437  -- another pipe
438  merge :: Pipe r i x m Void -> Pipe r x o m Void -> Pipe r i o m a
439  merge ix xo =
440    MkPipe $ \_a p c ->
441      -- FIXME: action a is not evaluated meaning the last action in a pipe
442      -- is ignored
443      let c' = unPipe ix absurd p
444          p' = unPipe xo absurd (Hyper c')
445       in p' c
446  
447  runPipe :: Pipe r () () m () -> m r
448  runPipe xs = unPipe xs h hk hc
449    where
450      h = const hyp
451      hk = rep (\k -> k ())
452      hc = rep const
453  
454  instance (MonadIO m) => MonadIO (Pipe r i o m) where
455    liftIO = lift . liftIO
456  
457  lhs :: Pipe () () Int IO Void
458  lhs = do
459    liftIO (putStrLn "Entered lhs")
460    liftIO $ putStrLn "(1) yield 1"
461    yield 1
462    liftIO $ putStrLn "(1) yield 2"
463    yield 2
464    halt (putStrLn $ "Halt 1")
465  
466  rhs :: Pipe () Int Int IO Void
467  rhs = do
468    liftIO (putStrLn "Entered rhs")
469    x <- await
470    liftIO $ putStrLn $ "(2) received " <> show x
471    yield $ x + 1
472    y <- await
473    liftIO $ putStrLn $ "(2) received " <> show y
474    yield $ x + 2
475    halt (putStrLn $ "Halt 2")
476  
477  rrhs :: Pipe () Int () IO Void
478  rrhs = do
479    x <- await
480    liftIO $ putStrLn $ "(3) received " <> show x
481    y <- await
482    liftIO $ putStrLn $ "(3) received " <> show y
483    halt (putStrLn $ "Halt 3")
484  
485  -- * Coroutines
486  
487  type Channel r i o = (o -> r) :-> (i -> r)
488  
489  type Suspension r i o = Channel r o i -> r
490  
491  newtype Co r i o m a = MkCo {route :: (a -> Channel (m r) o i -> m r) -> Channel (m r) o i -> m r}
492  
493  instance Functor (Co r i o m) where
494    f `fmap` (MkCo k) = MkCo $ \g -> k (g . f)
495  
496  instance Applicative (Co r i o m) where
497    pure a = MkCo $ \k -> k a
498    MkCo f <*> MkCo a = MkCo $ \k -> f (\g -> a (k . g))
499  
500  instance Monad (Co r i o m) where
501    return = pure
502    MkCo m >>= f = MkCo $ \k ->
503      m
504        ( \a -> case f a of
505            MkCo g -> g k
506        )
507  
508  instance MonadTrans (Co r i o) where
509    lift m = MkCo $ \k c -> m >>= \m' -> k m' c
510  
511  instance MonadCont (Co r i o m) where
512    callCC f = MkCo $ \s c ->
513      route (f $ \x -> MkCo $ \_ b -> s x b) s c
514  
515  yieldC :: o -> Co r i o m i
516  yieldC o = MkCo $ \k h -> hyp h (Hyper (flip k)) o
517  
518  mergeC :: Co r i x m Void -> (x -> Co r x o m Void) -> Co r i o m a
519  mergeC ix xo =
520    MkCo (\_ h -> route ix absurd (Hyper $ \h' x -> route (xo x) absurd (h <.> h')))
521  
522  awaitC :: (MonadCont m) => Co r i o m r -> m (Either r (o, i -> Co r i o m r))
523  awaitC c = callCC $ \k ->
524    Left
525      <$> route
526        c
527        (\x _ -> return x)
528        (Hyper (\h o -> k (Right (o, \i -> MkCo (\_ s -> hyp h s i)))))
529  
530  await' :: (MonadCont m) => Co Void i o m Void -> m (o, i -> Co Void i o m Void)
531  await' c = either absurd id <$> awaitC c
532  
533  runCo :: Co r i i m i -> m r
534  runCo c = route c idS hid
535  
536  idS :: i -> Suspension r i i
537  idS i c = hyp c hid i
538  
539  hid :: (i -> r) :-> (i -> r)
540  hid = rep id
541  
542  send :: forall m r i o. (MonadCont m) => Co r i o m r -> i -> m (Either r (o, Co r i o m r))
543  send c v = callCC $ \k ->
544    Left
545      <$> route
546        c
547        (\x _ -> return x)
548        (Hyper (\h o -> k (Right (o, MkCo (\_ s -> hyp h s v)))))
549  
550  class (Monad m) => MonadSay m where
551    say :: String -> m ()
552  
553  instance (Monad m, MonadWriter [String] m) => MonadSay m where
554    say = tell . (: [])
555  
556  gen :: (MonadSay m) => Co Void Int Int m Void
557  gen = forever $ do
558    lift $ say "in gen"
559    x <- yieldC 1
560    lift $ say $ "yielded 1, received " <> show x
561    x <- yieldC 2
562    lift $ say $ "yielded 2, received " <> show x
563    x <- yieldC 3
564    lift $ say $ "yielded 3, received " <> show x
565  
566  progC :: (MonadSay m, MonadCont m) => Co Void Int Int m Void -> m ()
567  progC g = do
568    send g 12 >>= \case
569      Left r -> say $ "coroutine done " <> show r
570      Right (x, kg) -> do
571        say "in prog"
572        (x, kg) <- await' g
573        say $ "received " <> show x
574        (x, kg) <- await' (kg 10)
575        say $ "sent 10, received " <> show x
576        (x, kg) <- await' (kg 20)
577        say $ "sent 20, received " <> show x
578        (x, kg) <- await' (kg 30)
579        say $ "sent 30, received " <> show x