File: Rigid.hs

package info (click to toggle)
haskell-selective 0.7.0.1-1
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 232 kB
  • sloc: haskell: 1,744; makefile: 6
file content (74 lines) | stat: -rw-r--r-- 2,188 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
{-# LANGUAGE DeriveFunctor, FlexibleInstances, GADTs #-}
module Teletype.Rigid where

import Prelude hiding (getLine, putStrLn)
import qualified Prelude as IO
import qualified Control.Monad as IO
import Control.Selective
import Control.Selective.Rigid.Free

-- See Section 5.2 of the paper: https://dl.acm.org/doi/10.1145/3341694.

-- | The classic @Teletype@ base functor.
data TeletypeF a = Read (String -> a) | Write String a deriving Functor

instance Eq (TeletypeF ()) where
    Read  _    == Read  _    = True
    Write x () == Write y () = x == y
    _ == _ = False

instance Show (TeletypeF a) where
    show (Read _)    = "Read"
    show (Write s _) = "Write " ++ show s

-- | Interpret 'TeletypeF' commands as 'IO' actions.
toIO :: TeletypeF a -> IO a
toIO (Read f)    = f <$> IO.getLine
toIO (Write s a) = a <$  IO.putStrLn s

-- | A Teletype program is a free selective functor on top of the base functor
-- 'TeletypeF'.
type Teletype a = Select TeletypeF a

-- | A convenient alias for reading a string.
getLine :: Teletype String
getLine = liftSelect (Read id)

-- | A convenient alias for writing a string.
putStrLn :: String -> Teletype ()
putStrLn s = liftSelect (Write s ())

-- | The ping-pong example from the introduction section of the paper
-- implemented using free selective functors.
--
-- @
-- > getEffects pingPongS
-- [Read,Write "pong"]
-- @
--
-- If can also be executed in IO:
--
-- @
-- > runSelect toIO pingPongS
-- hello
-- > runSelect toIO pingPongS
-- ping
-- pong
-- @
pingPongS :: Teletype ()
pingPongS = whenS (fmap ("ping"==) getLine) (putStrLn "pong")

------------------------------- Ping-pong example ------------------------------
-- | Monadic ping-pong, which has the desired behaviour, but cannot be
-- statically analysed.
pingPongM :: IO ()
pingPongM = IO.getLine >>= \s -> IO.when (s == "ping") (IO.putStrLn "pong")

-- | Applicative ping-pong, which always executes both effect, but can be
-- statically analysed.
pingPongA :: IO ()
pingPongA = IO.getLine *> IO.putStrLn "pong"

-- | A monadic greeting. Cannot be implemented using selective functors.
greeting :: IO ()
greeting = IO.getLine >>= \name -> IO.putStrLn ("Hello, " ++ name)