1

我试图搜索可能在某个任意位置包含元素(“$”,未定义)的对列表。我只想搜索那个特殊元素前面的列表部分,所以我尝试了这样的方法(已经打算将元素 n 和列表 xs 作为参数):

checkNotSameScope :: Env -> VarName -> Expr -> Expr
checkNotSameScope (xs:("$", Undefined):_) n e = if alreadyThere n xs then BoolLit False
                                                   else BoolLit True

但这不起作用;编译器似乎表明 (xs: ..) 仅处理在我的列表之前的 SINGLE 值。我不能使用 : 来表示列表的第一块;只有一个元素。回想起来,这是有道理的;否则,编译器怎么知道该怎么做?将“s”添加到“x”之类的东西不会神奇地产生多个元素!但是我该如何解决这个问题?

4

3 回答 3

5

不幸的是,即使使用智能编译器和语言,也无法避免一些编程......

在您的情况下,您似乎希望列表的一部分达到特定元素。更一般地说,要找到符合某些条件的列表,您可以使用标准库takeWhile函数。然后你可以alreadyThere在它上面运行:

checkNotSameScope :: Env -> VarName -> Expr -> Expr
checkNotSameScope xs n e = if alreadyThere n (takeWhile (/= ("$", Undefined)) xs)
                           then BoolLit False
                           else BoolLit True

("$", Undefined)对于没有出现的列表,它可能不是您想要的,所以要小心。

于 2012-10-14T17:34:13.677 回答
2

与 Joachim 的回答类似,您可以使用break,这将允许您检测何时("$", Undefined)不发生(如果有必要)。IE

checkNotSameScope xs n e = case break (== ("$", Undefined)) xs of
                             (_, [])  -> .. -- ("$", Undefined) didn't occur!
                             (xs', _) -> BoolLit . not $ alreadyThere n xs'

(注意,您在此解决方案中失去了一些懒惰,因为必须遍历列表直到("$", Undefined)或结束,以检查第一种情况。)

于 2012-10-14T17:52:03.863 回答
1

Haskell 不能开箱即用地进行这种模式匹配,尽管有一些语言可以使用active patterns ,例如CLIPS或 F# 。

但是我们可以使用 Haskell 现有的模式匹配能力来获得类似的结果。让我们首先定义一个名为 deconstruct 的函数,定义如下:

deconstruct :: [a] -> [([a], a, [a])]
deconstruct [] = []
deconstruct [x] = [([], x, [])]
deconstruct (x:xs) = ([], x, xs) : [(x:ys1, y, ys2) | (ys1, y, ys2) <- deconstruct xs]

这个函数所做的是将列表 xs 的所有分解为形式的三元组,(ys1, y, ys2)使得ys1 ++ [y] ++ ys2 == xs. 例如:

deconstruct [1..4] => [([],1,[2,3,4]),([1],2,[3,4]),([1,2],3,[4]),([1,2,3],4,[])]

使用它,您可以按如下方式定义您的函数:

checkNotSameScope xs n e =
    case [ys | (ys, ("$", Undefined), _) <- deconstruct xs] of
        [ys] -> BoolLit $ not $ alreadyThere n xs
        _    -> -- handle the case when ("$", Undefined) doesn't occur at all or more than once

我们可以使用do-notation来获得更接近您正在寻找的东西:

checkNotSameScope xs n e = BoolLit $ not $ any (alreadyThere n) prefixes
    where
        prefixes = do
            (xs, ("$", Undefined), _) <- deconstruct xs
            return xs

这里发生了几件事。首先,该prefixes变量将存储出现在该("$", Undefined)对之前的所有前缀列表 - 如果该对不在输入列表中,则没有xs。然后使用any函数,我们正在检查是否alreadyThere n为任何前缀提供 True 。剩下的就是完成你的函数逻辑。

于 2012-10-15T19:46:49.433 回答