-
Notifications
You must be signed in to change notification settings - Fork 0
/
ListChurch.hs
73 lines (62 loc) · 1.95 KB
/
ListChurch.hs
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
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE Rank2Types #-}
-- |
-- Module : ListChurch
-- Copyright : (c) Adrián Enríquez Ballester, 2021
--
-- This module defines a Church encoding
-- for @[]@ (i.e. list) values.
module Encoding.ListChurch
( ListChurch
, listChurch
, listUnchurch
, nil
, app
, hd
, isEmpty
) where
import Encoding (Encoding (from, to))
-- The following pragma avoids HLint hints
-- for simplifying our anonymous functions.
-- In this way we can write more clearly
-- anonymous functions which look like
-- lambda abstractions without HLint complains.
{-# ANN module "HLint: ignore" #-}
-- | The Church encoding type of an @[]@ as
-- an opaque type, just to be seen as an @[]@
-- alternative implementation in terms of
-- polymorphic lambda calculus terms.
newtype ListChurch a = ListChurch
(forall b. (a -> b -> b) -> b -> b)
-- | Instance for @'ListChurch'@ to be an
-- encoding of @[]@ values.
instance Encoding [a] (ListChurch a) where
from = listChurch
to = listUnchurch
-- | Encodes a @[]@ value into its
-- corresponding @'ListChurch'@.
listChurch :: [a] -> ListChurch a
listChurch as = ListChurch $ \c n -> foldr c n as
-- | Recovers the @[]@ value from a
-- @'ListChurch'@.
listUnchurch :: ListChurch a -> [a]
listUnchurch (ListChurch l) = l (:) []
-- | The empty @'ListChurch'@ value.
nil :: ListChurch a
nil = ListChurch $ \_ n -> n
-- | Concatenation of two @'ListChurch'@ values.
app :: ListChurch a -> ListChurch a -> ListChurch a
app (ListChurch l1) (ListChurch l2) =
ListChurch $ \c n -> l1 c (l2 c n)
-- | The first element of a nonempty @'ListChurch'@.
--
-- We have represented the possibility of failure
-- wrapping the result in @'Maybe'@ instead
-- of making this function partial.
hd :: ListChurch a -> Maybe a
hd (ListChurch l) =
l (\x _ -> Just x) Nothing
-- | Check if a @'ListChurch'@ is empty.
isEmpty :: ListChurch a -> Bool
isEmpty (ListChurch l) =
l (\_ _ -> False) True