2012-10-14 117 views
1

我试图通过可能在某个任意位置具有元素(“$”,未定义)的对的列表进行搜索。我想仅搜索在那个特殊元素的前面列表的一部分,所以我想是这样的(alreadyThere旨在采取元素n和列表XS作为参数):Haskell模式匹配难题

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

但这不行;编译器似乎表明(xs:..)只处理一个单独的值,并将我的列表前置。我不能使用:指示列表的第一个块;只有一个元素。回头看,这是有道理的;否则,编译器如何知道该怎么做?将“s”添加到“x”之类的东西并不会使多个元素神奇地变化!但我该如何解决这个问题?

+0

也许我应该问,“我怎样才能做到这一点没有模式匹配的另一种方式,因为这是不可能的?”哈斯克尔是非常聪明的人。 – nicole

回答

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)不发生名单,所以要小心。

+0

甚至是'checkNotSameScope xs n e = BoolLit。不是。已经在那里takeWhile(/ =(“$”,Undefined))$ xs' – pat

+0

没错。我只是修复了有问题的代码而没有阅读太多其他内容。 –

2

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

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

(NB。你失去了一些懒惰在该方案中,由于该表已被遍历直到("$", Undefined),或者到最后,检查尚属首例。)

0

哈斯克尔不能做这样的尽管有些语言可以像CLIPS或F#那样使用active patterns

但是我们可以使用Haskell现有的模式匹配功能来获得相似的结果。让我们先来定义这样定义的函数调用解构:

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 = BoolLit $ not $ any (alreadyThere n) prefixes 
    where 
     prefixes = do 
      (xs, ("$", Undefined), _) <- deconstruct xs 
      return xs 

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获得的东西更接近你在找什么

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