applicative regular expressions w/ the free alternative · 2020. 3. 9. ·...

78
Applicative Regular Expressions w/ the Free Alternative Justin Le (@mstk) C◦mp◦se Conference 2019, June 24

Upload: others

Post on 12-Sep-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions w/ the FreeAlternative

Justin Le (@mstk)

C◦mp◦se Conference 2019, June 24

Page 2: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Preface

Slide available at https://talks.jle.im.

Page 3: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Regular Expressions

(a|b)(cd)*e

Matches:I aeI acdcdcdeI bcde

Doesn’t match:I acdcdI abcdeI bce

Page 4: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Regular Expressions

(a|b)(cd)*e

Matches:I aeI acdcdcdeI bcde

Doesn’t match:I acdcdI abcdeI bce

Page 5: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

“Captures”

(a|b)(cd)*e

I ae →I acdcdcde →I bcde →

I ("a","")I ("a","cdcdcd")I ("b","cd")

Page 6: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

“Captures”

(a|b)(cd)*e

I ae →I acdcdcde →I bcde →

I ("a","")

I ("a","cdcdcd")I ("b","cd")

Page 7: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

“Captures”

(a|b)(cd)*e

I ae →I acdcdcde →I bcde →

I ("a","")I ("a","cdcdcd")

I ("b","cd")

Page 8: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

“Captures”

(a|b)(cd)*e

I ae →I acdcdcde →I bcde →

I ("a","")I ("a","cdcdcd")I ("b","cd")

Page 9: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

“Type-indexed” regular expressions.

type RegExp a-- ˆ type of "result"

char :: Char -> RegExp Charstring :: String -> RegExp String

runRegexp :: RegExp a -> String -> Maybe a

Page 10: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

“Type-indexed” regular expressions.

type RegExp a-- ˆ type of "result"

char :: Char -> RegExp Charstring :: String -> RegExp String

runRegexp :: RegExp a -> String -> Maybe a

Page 11: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

“Type-indexed” regular expressions.

type RegExp a-- ˆ type of "result"

char :: Char -> RegExp Charstring :: String -> RegExp String

runRegexp :: RegExp a -> String -> Maybe a

Page 12: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

“Type-indexed” regular expressions.

type RegExp a-- ˆ type of "result"

char :: Char -> RegExp Charstring :: String -> RegExp String

runRegexp :: RegExp a -> String -> Maybe a

Page 13: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

char :: Char -> RegExp Charstring :: String -> RegExp String(<|>) :: RegExp a -> RegExp a -> RegExp amany :: RegExp a -> RegExp [a]

myRegexp :: RegExp (Char, [String])myRegexp = (,) <$> (char 'a' <|> char 'b')

<*> many (string "cd")<* char 'e'

runRegexp myRegexp :: String -> Maybe (Char, [String])

Page 14: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

char :: Char -> RegExp Charstring :: String -> RegExp String(<|>) :: RegExp a -> RegExp a -> RegExp amany :: RegExp a -> RegExp [a]

myRegexp :: RegExp (Char, [String])myRegexp = (,) <$> (char 'a' <|> char 'b')

<*> many (string "cd")<* char 'e'

runRegexp myRegexp :: String -> Maybe (Char, [String])

Page 15: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

runRegexp myRegexp "ae"Just ('a', [])

runRegexp myRegexp "acdcdcde"Just ('a', ["cd","cd","cd"])

runRegexp myRegexp "bcde"Just ('b', ["cd"])

runRegexp myRegexp "acdcd"Nothing

Page 16: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

myRegexp2 :: RegExp (Bool, Int)myRegexp2 = (,) <$> ((False <$ char 'a') <|> (True <$ char 'b'))

<*> fmap length (many (string "cd"))<* char 'e'

runRegexp myRegexp2 "ae"Just (False, 0)

runRegexp myRegexp2 "acdcdcde"Just (False, 3)

runRegexp myRegexp2 "bcde"Just (True, 1)

Page 17: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Applicative Regular Expressions

myRegexp2 :: RegExp (Bool, Int)myRegexp2 = (,) <$> ((False <$ char 'a') <|> (True <$ char 'b'))

<*> fmap length (many (string "cd"))<* char 'e'

runRegexp myRegexp2 "ae"Just (False, 0)

runRegexp myRegexp2 "acdcdcde"Just (False, 3)

runRegexp myRegexp2 "bcde"Just (True, 1)

Page 18: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What’s so Regular about Regexps?

Regular Language Base Members

1. Empty language: Always fails to match2. Empty string: Always succeeds, consumes nothing3. Literal: Matches and consumes a given char

Regular Language Operations

1. Concatenation: RS, sequence one after the other2. Alternation: R|S, one or the other3. Kleene Star: R*, the repetition of R

Page 19: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What’s so Regular about Regexps?

Regular Language Base Members

1. Empty language: Always fails to match2. Empty string: Always succeeds, consumes nothing3. Literal: Matches and consumes a given char

Regular Language Operations

1. Concatenation: RS, sequence one after the other2. Alternation: R|S, one or the other3. Kleene Star: R*, the repetition of R

Page 20: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What’s so Regular about Regexps?

Regular Language Base Members

1. Empty language: Always fails to match2. Empty string: Always succeeds, consumes nothing3. Literal: Matches and consumes a given char

Regular Language Operations

1. Concatenation: RS, sequence one after the other2. Alternation: R|S, one or the other3. Kleene Star: R*, the repetition of R

Page 21: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Page 22: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Page 23: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Page 24: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Components of a RegularLanguage1. Empty language: empty

2. Empty string: pure x3. Literal: ???4. Concatenation: <*>5. Alternation: <|>6. Repetition: many

Page 25: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Components of a RegularLanguage1. Empty language: empty2. Empty string: pure x

3. Literal: ???4. Concatenation: <*>5. Alternation: <|>6. Repetition: many

Page 26: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Components of a RegularLanguage1. Empty language: empty2. Empty string: pure x3. Literal: ???

4. Concatenation: <*>5. Alternation: <|>6. Repetition: many

Page 27: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Components of a RegularLanguage1. Empty language: empty2. Empty string: pure x3. Literal: ???4. Concatenation: <*>

5. Alternation: <|>6. Repetition: many

Page 28: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Components of a RegularLanguage1. Empty language: empty2. Empty string: pure x3. Literal: ???4. Concatenation: <*>5. Alternation: <|>

6. Repetition: many

Page 29: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

An Alternative Perspective

class Functor f => Applicative f where-- | Always succeed, consuming nothingpure :: a -> f a-- | Concatenation(<*>) :: f (a -> b) -> f a -> f b

class Applicative f => Alternative f where-- | Always fails to matchempty :: f a-- | Alternation(<|>) :: f a -> f a -> f a-- | Reptitionmany :: f a -> f [a]

Components of a RegularLanguage1. Empty language: empty2. Empty string: pure x3. Literal: ???4. Concatenation: <*>5. Alternation: <|>6. Repetition: many

Page 30: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Functor combinator-style

I Define a primitive type

type Prim a

I Add the structure you need

I If this structure is from a typeclass, use the free structure ofthat typeclass

Page 31: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Functor combinator-style

I Define a primitive type

type Prim a

I Add the structure you need

I If this structure is from a typeclass, use the free structure ofthat typeclass

Page 32: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Functor combinator-style

I Define a primitive type

type Prim a

I Add the structure you needI If this structure is from a typeclass, use the free structure of

that typeclass

Page 33: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Easy as 1, 2, 3

-- | Free Alternative, from 'free'data Alt :: (Type -> Type) -> (Type -> Type)

-- ˆ take a Functor; ˆ return a Functorinstance Functor (Alt f)instance Applicative (Alt f)instance Alternative (Alt f)

liftAlt :: Prim a -> Alt Prim

data Prim a = Prim Char aderiving Functor

type RegExp = Alt Prim

char :: Char -> RegExp Charchar c = liftAlt (Prim c c)

Page 34: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Easy as 1, 2, 3

-- | Free Alternative, from 'free'data Alt :: (Type -> Type) -> (Type -> Type)

-- ˆ take a Functor; ˆ return a Functorinstance Functor (Alt f)instance Applicative (Alt f)instance Alternative (Alt f)

liftAlt :: Prim a -> Alt Prim

data Prim a = Prim Char aderiving Functor

type RegExp = Alt Prim

char :: Char -> RegExp Charchar c = liftAlt (Prim c c)

Page 35: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Unlimited Power

empty :: RegExp apure :: a -> RegExp achar :: Char -> RegExp Char(<*>) :: RegExp (a -> b) -> RegExp a -> RegExp b(<|>) :: RegExp a -> RegExp a -> RegExp amany :: RegExp a -> RegExp [a]

string :: String -> RegExp Stringstring = traverse char

digit :: RegExp Intdigit = asum [ intToDigit i <$ char i | i <- [0..9] ]

Page 36: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Unlimited Power

empty :: RegExp apure :: a -> RegExp achar :: Char -> RegExp Char(<*>) :: RegExp (a -> b) -> RegExp a -> RegExp b(<|>) :: RegExp a -> RegExp a -> RegExp amany :: RegExp a -> RegExp [a]

string :: String -> RegExp Stringstring = traverse char

digit :: RegExp Intdigit = asum [ intToDigit i <$ char i | i <- [0..9] ]

Page 37: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Parsing

Options

1. Interpret into an Alternative instance, “offloading” the logic

I Analogy: Process a list using foldMap2. Direct pattern match on structure constructors (Haskell 101)

I Analogy: Process a list using pattern matching and recursion

Page 38: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Parsing

Options

1. Interpret into an Alternative instance, “offloading” the logicI Analogy: Process a list using foldMap

2. Direct pattern match on structure constructors (Haskell 101)

I Analogy: Process a list using pattern matching and recursion

Page 39: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Parsing

Options

1. Interpret into an Alternative instance, “offloading” the logicI Analogy: Process a list using foldMap

2. Direct pattern match on structure constructors (Haskell 101)

I Analogy: Process a list using pattern matching and recursion

Page 40: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Parsing

Options

1. Interpret into an Alternative instance, “offloading” the logicI Analogy: Process a list using foldMap

2. Direct pattern match on structure constructors (Haskell 101)I Analogy: Process a list using pattern matching and recursion

Page 41: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?

class Semigroup m where(<>) :: m -> m -> m

class Monoid m wheremempty :: m

type FreeMonoid = [] :: Type -> Type-- ˆ take a type; ˆ return a type

instance Semigroup (FreeMonoid a)instance Monoid (FreeMonoid a)

injectFM :: a -> FreeMonoid arunFM :: Monoid m => (a -> m) -> (FreeMonoid a -> m)

runFM f-- ˆ substitute injectFM for f

(:[]) :: a -> [a]foldMap :: Monoid m => (a -> m) -> ([a] -> m)

Page 42: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?class Semigroup m where

(<>) :: m -> m -> mclass Monoid m where

mempty :: m

type FreeMonoid = [] :: Type -> Type-- ˆ take a type; ˆ return a type

instance Semigroup (FreeMonoid a)instance Monoid (FreeMonoid a)

injectFM :: a -> FreeMonoid arunFM :: Monoid m => (a -> m) -> (FreeMonoid a -> m)

runFM f-- ˆ substitute injectFM for f

(:[]) :: a -> [a]foldMap :: Monoid m => (a -> m) -> ([a] -> m)

Page 43: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?class Semigroup m where

(<>) :: m -> m -> mclass Monoid m where

mempty :: m

type FreeMonoid = [] :: Type -> Type-- ˆ take a type; ˆ return a type

instance Semigroup (FreeMonoid a)instance Monoid (FreeMonoid a)

injectFM :: a -> FreeMonoid arunFM :: Monoid m => (a -> m) -> (FreeMonoid a -> m)

runFM f-- ˆ substitute injectFM for f

(:[]) :: a -> [a]foldMap :: Monoid m => (a -> m) -> ([a] -> m)

Page 44: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?

myMon :: FreeMonoid IntmyMon = injectFM 1 <> mempty <> injectF1 2 <> injectF1 3 <> injectF1 4

foldMap Sum myMon -- mempty = 0, <> = +Sum 1 + Sum 0 + Sum 2 + Sum 3 + Sum 4Sum 10

foldMap Product myMon -- mempty = 1, <> = *Product 1 * Product 1 * Product 2 * Product 3 * Product 4Product 24

foldMap Max myMon -- mempty = minBound, <> = maxMax 1 `max` Max minBound `max` Max 2 `max` Max 3 `max` Max 4Max 4

Page 45: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?

myMon :: FreeMonoid IntmyMon = injectFM 1 <> mempty <> injectF1 2 <> injectF1 3 <> injectF1 4

foldMap Sum myMon -- mempty = 0, <> = +Sum 1 + Sum 0 + Sum 2 + Sum 3 + Sum 4Sum 10

foldMap Product myMon -- mempty = 1, <> = *Product 1 * Product 1 * Product 2 * Product 3 * Product 4Product 24

foldMap Max myMon -- mempty = minBound, <> = maxMax 1 `max` Max minBound `max` Max 2 `max` Max 3 `max` Max 4Max 4

Page 46: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?

myMon :: FreeMonoid IntmyMon = injectFM 1 <> mempty <> injectF1 2 <> injectF1 3 <> injectF1 4

foldMap Sum myMon -- mempty = 0, <> = +Sum 1 + Sum 0 + Sum 2 + Sum 3 + Sum 4Sum 10

foldMap Product myMon -- mempty = 1, <> = *Product 1 * Product 1 * Product 2 * Product 3 * Product 4Product 24

foldMap Max myMon -- mempty = minBound, <> = maxMax 1 `max` Max minBound `max` Max 2 `max` Max 3 `max` Max 4Max 4

Page 47: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?

myMon :: FreeMonoid IntmyMon = injectFM 1 <> mempty <> injectF1 2 <> injectF1 3 <> injectF1 4

foldMap Sum myMon -- mempty = 0, <> = +Sum 1 + Sum 0 + Sum 2 + Sum 3 + Sum 4Sum 10

foldMap Product myMon -- mempty = 1, <> = *Product 1 * Product 1 * Product 2 * Product 3 * Product 4Product 24

foldMap Max myMon -- mempty = minBound, <> = maxMax 1 `max` Max minBound `max` Max 2 `max` Max 3 `max` Max 4Max 4

Page 48: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What is freeness?

type Alt f a

-- | Analog to (:[])liftAlt :: f a -> Alt f a

-- | Analog to foldMaprunAlt :: Alternative g

=> (forall b. f a -> g a)-> (Alt f a -> g a)

runAlt f-- ˆ substitute liftAlt for f

Page 49: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Goal

Find an Alternative where:I Prim a = consumption

I <*> = sequencing consumptionI <|> = backtracking

Page 50: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Goal

Find an Alternative where:I Prim a = consumptionI <*> = sequencing consumption

I <|> = backtracking

Page 51: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Goal

Find an Alternative where:I Prim a = consumptionI <*> = sequencing consumptionI <|> = backtracking

Page 52: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Hijacking StateT

StateT [Char] Maybe

I Prim a can be interpreted as consumption of stateI <*> sequences consumption of stateI <|> is backtracking of state

Page 53: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Hijacking StateT

processPrim :: Prim a -> StateT String Maybe aprocessPrim (Prim c x) = do

d:ds <- get -- ˆ match on streamguard (c == d) -- ˆ fail unless matchput ds -- ˆ update streamreturn x -- ˆ return result value

matchPrefix :: Regexp a -> String -> Maybe amatchPrefix re = evalStateT (runAlt processPrim re)

Page 54: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

This works?

Yes!

matchPrefix myRegexp2 "ae"Just (False, 0)

matchPrefix myRegexp2 "acdcdcde"Just (False, 3)

matchPrefix myRegexp2 "bcde"Just (True, 1)

Page 55: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

This works?

Yes!

matchPrefix myRegexp2 "ae"Just (False, 0)

matchPrefix myRegexp2 "acdcdcde"Just (False, 3)

matchPrefix myRegexp2 "bcde"Just (True, 1)

Page 56: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What just happened?

data Prim a = Prim Char aderiving Functor

type RegExp = Alt Prim

matchPrefix :: RegExp a -> String -> Maybe amatchPrefix re = evalStateT (runAlt processPrim re)

whereprocessPrim (Prim c x) = do

d:ds <- getguard (c == d)put dspure x

Fits in a tweet!

Page 57: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What just happened?

data Prim a = Prim Char aderiving Functor

type RegExp = Alt Prim

matchPrefix :: RegExp a -> String -> Maybe amatchPrefix re = evalStateT (runAlt processPrim re)

whereprocessPrim (Prim c x) = do

d:ds <- getguard (c == d)put dspure x

Fits in a tweet!

Page 58: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What just happened?

1. Offload Alternative functionality to StateT: empty, <*>,pure, empty, many.

2. Provide Prim-processing functionality with processPrim:liftAlt.

Page 59: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What just happened?

1. Offload Alternative functionality to StateT: empty, <*>,pure, empty, many.

2. Provide Prim-processing functionality with processPrim:liftAlt.

Page 60: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

1. Interpretation-invariant structure

2. Actually meaningful types

I StateT String Maybe is not a regular expression type.notARegexp :: StateT String Maybe ()notARegexp = put "hello" -- no regular expression

I Alt Prim is a regular expression type.

Page 61: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

1. Interpretation-invariant structure2. Actually meaningful types

I StateT String Maybe is not a regular expression type.notARegexp :: StateT String Maybe ()notARegexp = put "hello" -- no regular expression

I Alt Prim is a regular expression type.

Page 62: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

1. Interpretation-invariant structure2. Actually meaningful types

I StateT String Maybe is not a regular expression type.notARegexp :: StateT String Maybe ()notARegexp = put "hello" -- no regular expression

I Alt Prim is a regular expression type.

Page 63: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

1. Interpretation-invariant structure2. Actually meaningful types

I StateT String Maybe is not a regular expression type.notARegexp :: StateT String Maybe ()notARegexp = put "hello" -- no regular expression

I Alt Prim is a regular expression type.

Page 64: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Direct matching

newtype Alt f a = Alt { alternatives :: [AltF f a] }

data AltF f a = forall r. Ap (f r) (Alt f (r -> a))| Pure a

-- | Chain of <|>snewtype Alt f a

= Choice (AltF f a) (Alt f a ) -- ˆ cons| Empty -- ˆ nil

-- | Chain of <*>sdata AltF f a

= forall r. Ap (f r ) (Alt f (r -> a)) -- ˆ cons| Pure a -- ˆ nil

Page 65: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Direct matching

newtype Alt f a = Alt { alternatives :: [AltF f a] }

data AltF f a = forall r. Ap (f r) (Alt f (r -> a))| Pure a

-- | Chain of <|>snewtype Alt f a

= Choice (AltF f a) (Alt f a ) -- ˆ cons| Empty -- ˆ nil

-- | Chain of <*>sdata AltF f a

= forall r. Ap (f r ) (Alt f (r -> a)) -- ˆ cons| Pure a -- ˆ nil

Page 66: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Direct Matching

matchAlts :: RegExp a -> String -> Maybe amatchAlts (Alt res) xs = asum [ matchChain re xs | re <- res ]

matchChain :: AltF Prim a -> String -> Maybe amatchChain (Ap (Prim c x) next) cs = _matchChain (Pure x) cs = _

Page 67: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Direct Matching

matchAlts :: RegExp a -> String -> Maybe amatchAlts (Alt res) xs = asum [ matchChain re xs | re <- res ]

matchChain :: AltF Prim a -> String -> Maybe amatchChain (Ap (Prim c x) next) cs = _matchChain (Pure x) cs = _

Page 68: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

One game of Type Tetris later. . .

matchChain :: AltF Prim a -> String -> Maybe amatchChain (Ap (Prim c x) next) cs = case cs of

[] -> Nothingd:ds | c == d -> matchAlts (($ x) <$> next) ds

| otherwise -> NothingmatchChain (Pure x) _ = Just x

Page 69: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

This works?

Yes!

matchChain myRegexp2 "ae"Just (False, 0)

matchChain myRegexp2 "acdcdcde"Just (False, 3)

matchChain myRegexp2 "bcde"Just (True, 1)

Page 70: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

This works?

Yes!

matchChain myRegexp2 "ae"Just (False, 0)

matchChain myRegexp2 "acdcdcde"Just (False, 3)

matchChain myRegexp2 "bcde"Just (True, 1)

Page 71: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

I First-class program rewriting, Haskell 101-style

I Normalizing representation

I Equivalence in meaning = equivalence in structure

-- | Not regularizingdata RegExp a = Empty

| Pure a| Prim Char a| forall r. Seq (RegExp a) (RegExp (r -> a))| Union (RegExp a) (RegExp a)| Many (RegExp a)

-- a|(b|c) /= (a|b)|c

Page 72: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

I First-class program rewriting, Haskell 101-styleI Normalizing representation

I Equivalence in meaning = equivalence in structure

-- | Not regularizingdata RegExp a = Empty

| Pure a| Prim Char a| forall r. Seq (RegExp a) (RegExp (r -> a))| Union (RegExp a) (RegExp a)| Many (RegExp a)

-- a|(b|c) /= (a|b)|c

Page 73: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

I First-class program rewriting, Haskell 101-styleI Normalizing representation

I Equivalence in meaning = equivalence in structure

-- | Not regularizingdata RegExp a = Empty

| Pure a| Prim Char a| forall r. Seq (RegExp a) (RegExp (r -> a))| Union (RegExp a) (RegExp a)| Many (RegExp a)

-- a|(b|c) /= (a|b)|c

Page 74: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

I First-class program rewriting, Haskell 101-styleI Normalizing representation

I Equivalence in meaning = equivalence in structure

-- | Not regularizingdata RegExp a = Empty

| Pure a| Prim Char a| forall r. Seq (RegExp a) (RegExp (r -> a))| Union (RegExp a) (RegExp a)| Many (RegExp a)

-- a|(b|c) /= (a|b)|c

Page 75: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

What do we gain?

I First-class program rewriting, Haskell 101-styleI Normalizing representation

I Equivalence in meaning = equivalence in structure

-- | Not regularizingdata RegExp a = Empty

| Pure a| Prim Char a| forall r. Seq (RegExp a) (RegExp (r -> a))| Union (RegExp a) (RegExp a)| Many (RegExp a)

-- a|(b|c) /= (a|b)|c

Page 76: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Free your mind

Is this you?“My problem is modeled by some (commonly occurring)structure over some primitive base.”

I Use a “functor combinator”!

I If your structure comes from a typeclass, use a free structure!

Page 77: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Free your mind

Is this you?“My problem is modeled by some (commonly occurring)structure over some primitive base.”

I Use a “functor combinator”!I If your structure comes from a typeclass, use a free structure!

Page 78: Applicative Regular Expressions w/ the Free Alternative · 2020. 3. 9. · ApplicativeRegularExpressions “Type-indexed”regularexpressions. type RegExpa-- ˆ type of "result" char

Further Reading

I Blog post:https://blog.jle.im/entry/free-applicative-regexp.html

I Functor Combinatorpedia:https://blog.jle.im/entry/functor-combinatorpedia.html

I free: https://hackage.haskell.org/package/freeI functor-combinators:

https://hackage.haskell.org/package/functor-combinatorsI Slides: https://talks.jle.im/composeconf-2019/