4

我想在 Haskell 中实现一个不区分顺序的功能应用程序版本。通过一点背景知识:自然语言语义中的一个突出传统(源自 Richard Montague 等)将各种类型的 lambda 函数指定为表达式的语义值 (sv's)。句子的真值是通过对句子成分的 sv 执行功能应用来计算的。举一个简单的例子,考虑:

tl = [1..10]

bill :: Int
bill = 1

tall :: Int -> Bool
tall = \x -> x `elem` tl

将句子“Bill is high”想象成一棵树,左叶被“Bill”占据,右叶被“tall”占据。我们通过将右叶的 sv应用于叶的 sv来计算句子的真值。现在考虑'Some man is high':这里左叶被'some man'占据[其sv类型为:: (Int -> Bool) -> Bool],右叶被'tall'占据[其 sv 的类型为 :: (Int -> Bool)]。我们通过将左叶的 sv应用于叶的 sv来计算句子的真值。

因此,在这个系统中,给定一棵具有左叶a和右叶b的树,我们首先检查哪个叶在另一个的域中,然后相应地应用功能应用:如果a在b的域中,我们做b (a),而如果b在a的域中,我们做a(b)

我将如何在 Haskell 中实现这种“顺序不敏感”的功能应用程序?我编写了一些函数,通过解析结果来确定哪个叶子在另一个域中

show (typeOf a)

对于一片叶子 a。然而,这在我看来是不必要的麻烦。如果您尝试评估,Ghci 会给出错误

bill tall

因此,检查哪一项在另一项的域中的一种简单方法是尝试将一项应用于另一项,并查看是否导致错误/异常。那么,我的问题是:如何捕获由类型不匹配导致的异常?也就是说,我如何捕获这种非 IO 异常?

4

2 回答 2

7

您无法在运行时捕获类型不匹配;这是一个编译时错误。(至少,不是不使用 ghc-api 在运行时编译代码。 ghci它是 ghc-api 的包装器,这就是它可以做到这一点的原因。)您需要找到一种方法来在 ADT 中捕获这种类型的区别来做它在运行时,或者可能使用类型类(但这会引入其他复杂性)。

于 2012-04-24T06:10:06.353 回答
6

您可能会通过一些类型类扩展获得很长的路要走:

{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies          #-}

class Copula l r where
  type Sem l r :: *
  is :: l -> r -> Sem l r

instance Copula (a -> b) a where
  type Sem (a -> b) a = b
  is = ($)

instance Copula a (a -> b) where
  type Sem a (a -> b) = b
  is = flip ($)   

例如,如果我们现在定义

bill :: Int
bill = 1

tall :: Int -> Bool
tall = \x -> x `elem` tl

someMan :: (Int -> Bool) -> Bool
someMan = flip any [1 .. 20]

allMan :: (Int -> Bool) -> Bool
allMan = flip all [1 .. 20]

我们得到

> bill `is` tall
True

> someMan `is` tall
True

> allMan `is` tall
False

直截了当,与

are :: Copula l r => l -> r -> Sem l r
are = is

我们能做的

> someMan `are` tall
True

> allMan `are` tall
False

这可能看起来更好一些。

注意:虽然这看起来很简洁,但总的来说,在多态上下文中,类型检查器需要相当多的帮助来确定要做什么。例如

> [] `is` null

<interactive>:37:4:                                                              
    No instance for (Copula [a0] ([a1] -> Bool))
      arising from a use of `is'
    Possible fix:
      add an instance declaration for (Copula [a0] ([a1] -> Bool))
    In the expression: [] `is` null
    In an equation for `it': it = [] `is` null

尽管

> ([] :: [Int]) `is` (null :: [Int] -> Bool)
True
于 2012-04-24T09:33:17.940 回答