2012-10-14 121 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。剩下的就是完成你的函數的邏輯。