Applicative categorial grammar

Table of Contents

1. Review

We recently introduced applicative categorial grammar, which we are using to (a) give syntactic analyses of a fragment of English, and (b) map the syntactic derivations (or structures) assigned to expressions via such analyses onto semantic representations of some kind. Such representations include, e.g., simply typed λ-terms and/or model-theoretic constructions (like entities and functions, etc.), as we've seen. We will explore more options going forward!

1.1. Encoding applicative categorial grammar

To start out, we introduce a set of categories. This set is defined to comprise base categories, like NP, N, and S, as well as complex categories, like c1 :\: c2 and c1 :/∶ c2 (given categories c1 and c2).

data Cat = NP | N | S
         | Cat :\: Cat
         | Cat :/: Cat

Here, NP is meant to encode the category of noun phrases (e.g., julian, the dog), N, the category of nouns (e.g., dog), and S, the category of full sentences (e.g., julian saw the dog). In terms of these categories, we can encode the notion a word—that is, an atomic expression—as a constructor that associates a String with a Cat. (Note that I've renamed the data type encoding categories at the term level from Lol c to IsA c, in light of Aaron's comment.)

data Word (c :: Cat) = Word String (IsA c)

data IsA (c :: Cat) where
  IsAnNP :: IsA NP
  IsAnN :: IsA N
  IsAnS :: IsA S
  (::\::) :: IsA c1 -> IsA c2 -> IsA (c1 :\: c2)
  (::/::) :: IsA c1 -> IsA c2 -> IsA (c1 :/: c2)

For example, the word slept, we can encode as Word "slept" (IsAnNP ::\:: IsAnS), taking into account that slept is a verb phrase. Meanwhile, julian, we can encode as Word "julian" IsAnNP, taking into account that julian is a noun phrase. By the way, let's also include Show instances.

instance Show (IsA c) where
  show IsAnNP = "np"
  show IsAnN = "n"
  show IsAnS = "s"
  show (c1 ::\:: c2) = "(" ++ show c1 ++ "\\" ++ show c2 ++ ")"
  show (c1 ::/:: c2) = "(" ++ show c1 ++ "/" ++ show c2 ++ ")"

instance Show (Word c) where
  show (Word s c) = "(" ++ s ++ " ⊢ " ++ show c ++ ")"

To put words together, we need a grammar of expressions. Thus we also provide the data type Expr c (with its associated Show instance).

data Expr (c :: Cat) where
  Lex :: Word c -> Expr c
  AppL :: Expr c1 -> Expr (c1 :\: c2) -> Expr c2
  AppR :: Expr (c2 :/: c1) -> Expr c1 -> Expr c2

instance Show (Expr c) where
  show (Lex w) = show w
  show (AppL e1 e2) = "(" ++ show e1 ++ " ◃ " ++ show e2 ++ ")"
  show (AppR e1 e2) = "(" ++ show e1 ++ " ▹ " ++ show e2 ++ ")"

Now we can analyze such sentences as, e.g., julian slept and julian taught carina:

>>> (AppL (Lex (Word "julian" IsAnNP)) (Lex (Word "slept" (IsAnNP ::\:: IsAnS))))
((julian  np)  (slept  (np\s)))
>>> (AppL (Lex (Word "julian" IsAnNP)) (AppR (Lex (Word "taught" ((IsAnNP ::\:: IsAnS) ::/:: IsAnNP))) (Lex (Word "carina" IsAnNP))))
((julian  np)  ((taught  ((np\s)/np))  (carina  np)))

Absolutely amazing.

1.2. Interpreting English into the simply typed λ-calculus

We can interpret such expressions into λ-calculus in terms of a type homomorphism SemType, given atomic types E and T.

type family SemType (c :: Cat) where
  SemType NP = E
  SemType S = T
  SemType N = E :-> T
  SemType (c1 :\: c2) = SemType c1 :-> SemType c2
  SemType (c2 :/: c1) = SemType c1 :-> SemType c2

Thus for example, verb phrases—that is, expressions of category NP :\: S—are given the semantic type SemType (NP :\: S) = SemType NP :-> SemType S = E :-> T, putting them on a par with nouns, semantically.

We should additionally begin adding constants to our λ-calculus to encode the meanings of basic English expressions. Thus we define a data type Constant.

data Constant:: Type) where
  Dog :: Constant (E :-> T)
  Sleep :: Constant (E :-> T)
  Teach :: Constant (E :-> (E :-> T))
  C :: Constant E
  J :: Constant E

We now also need an additional constructor in our encoding of the λ-calculus, in order to inject constants into the data type.

data Term:: Context) (φ :: Type) where
  Var :: In φ γ -> Term γ φ
  Lam :: Term (Con φ γ) ψ -> Term γ (φ :-> ψ)
  App :: Term γ (φ :-> ψ) -> Term γ φ -> Term γ ψ
  Con :: Constant φ -> Term γ φ

Note that the contexts in which constants are well typed are arbitrary by design. This property allows us to use them anywhere inside a λ-term.

We may now write a function interpWord to interpret words of English into the λ-calculus, along with an associated function interpExpr, which extends the interpretation of words to an interpretation of entire complex expressions.

interpWord :: Word c -> Term Empty (SemType c)
interpWord (Word "carina" IsAnNP) = Con C                       -- ⟦'carina'⟧ = c
interpWord (Word "julian" IsAnNP) = Con J                       -- ⟦'julian'⟧ = j
interpWord (Word "dog" IsAnN) = Lam (App (Con Dog) (Var First)) -- ⟦'dog'⟧ = λx.dog(x)
interpWord (Word "slept" (IsAnNP ::\:: IsAnS)) =                -- ⟦'slept'⟧ = λx.sleep(x)
  Lam (App (Con Sleep) (Var First))
interpWord (Word "taught" ((IsAnNP ::\:: IsAnS) ::/:: IsAnNP)) = -- ⟦'taught'⟧ = λx, y.teach(x)(y)
  Lam (Lam (App (App (Con Teach) (Var (Next First))) (Var First)))


interpExpr :: Expr c -> Term Empty (SemType c)
interpExpr (Lex w) = interpWord w
interpExpr (AppL e1 e2) = App (interpExpr e2) (interpExpr e1)
interpExpr (AppR e1 e2) = App (interpExpr e1) (interpExpr e2)

For example, you can interpret julian taught carina by doing

>>> interpExpr (AppL (Lex (Word "julian" IsAnNP)) (AppR (Lex (Word "taught" ((IsAnNP ::\:: IsAnS) ::/:: IsAnNP))) (Lex (Word "carina" IsAnNP))))
App (App (Lam (Lam (App (App (Con Teach) (Var (Next First))) (Var First)))) (Con C)) (Con J) -- (λx, y.teach(x)(y)) c j

Compare to what you get if you also apply normalForm at the top:

>>> normalForm (interpExpr (AppL (Lex (Word "julian" IsAnNP)) (AppR (Lex (Word "taught" ((IsAnNP ::\:: IsAnS) ::/:: IsAnNP))) (Lex (Word "carina" IsAnNP)))))
App (App (Con Teach) (Con C)) (Con J) -- teach(c)(j)

Neat.

1.3. Exercise

Extend the above fragment in order to give an analysis (including an interpretation) of the sentence carina saw the happy dog.

Author: Julian Grove

Created: 2023-10-28 Sat 21:07

Validate