2012-10-11 43 views
1

我正在編寫一個Haskell函數,它接收一個字符串列表並返回一個包含前兩個字符串作爲結果的元組的列表。因此,一個例子輸出爲:包含列表中前兩個字符串作爲元組的返回列表

listtuple ["bride", "zilla", "crazy", "women"] = [("bride", "villa")] 
listtuple ["basketball", "football"] = [("basketball", "football")] 

我想接近它,像這樣的方式:

listtuple :: Eq a => [Str a] -> [(Str a, Str a)] 
listtuple xs = [(x,y) | x <- xs !! 0, y <- xs !! 1] 

基本上我計算過,我可以隨便挑中的第一和第二索引的元素該列表,但我收到錯誤。這裏有幫助嗎?

回答

7

什麼你可能想要做的是這樣的:

listtuple xs = 
    let x = xs !! 0 
     y = xs !! 1 
    in (x, y) 

請注意,這不是同樣的事情,你寫什麼。其原因是,你寫的列表中理解轉化爲以下:

do x <- xs !! 0 -- Treat the first element of xs as a list 
    y <- xs !! 1 -- Treat the second element of xs as a list 
    return (x, y) 

這說明了一個問題:你是治療xs !! 0xs !! 1的名單時,他們沒有列出。xs !! 0只是一個單一的元素,所以如果你想聲明的是x等於xs !! 0,您可以使用:

let x = xs !! 0 
in <some expression that uses x> 

的列表<-理解語法不這樣做同樣的事情,我建議你避開名單理解,直到你理解列表單子如何工作,因爲編譯器將列表解析轉換爲列表monad。

現在,第二個問題是您使用(!!)。您應該避開部分功能,如(!!),並專注於使用模式匹配來解決這些問題。慣用的方式做你要求什麼是模式匹配的前兩個元素:

listtuple (x:y:_) = (x, y) 

...除了將失敗在包含少於兩個元素的列表。您防範這種由存儲結果爲Maybe,其中Just包裝了一個成功的結果,並Nothing表示失敗:

listtuple :: [a] -> Maybe (a, a) 
listtuple (x:y:_) = Just (x, y) 
listtuple _  = Nothing 
1

我的代碼中存在一些可以看到的錯誤,但是如果您有關於代碼無法正常工作的具體問題,請告訴我。

首先,您提供的類型簽名無效。 String是一個無參數數據結構,Str a不算什麼,除非你自己定義了一個名爲Str的數據結構。 String列表將不需要您提供的等式約束,因爲編譯器已知道StringEq的實例。其次,你正在使用列表理解語法(看起來像)where子句的地方。考慮到在綁定元素x之前,Haskell將嘗試評估xs !! 0。因爲這是一個列表理解,所以這可能不會立即失敗,因爲xsString的列表(實際上是Char的列表),但是最終將得到從xs中的第一個和第二個字符串中取出的元組Char

這是一個簡單的解決方案,使用模式匹配生成你想要的。

listtuple :: [a] -> [(a, a)] 
listtuple (x:y:zs) = [(x, y)] 

請注意,這不是一個全部函數(即,如果您傳遞一個列表少於兩個元素,它將導致錯誤)。當一個空的或一個元素列表被傳遞給它時,這可能是通過返回空列表來完成的,它是否可以滿足您的預期目的?

下面是一個替代版本,您可能會發現它適合您用來編寫自己版本的心智模型。

listtuple xs = [(x, y)] 
      where 
       x = xs !! 0 
       y = xs !! 1 
10

簡單的答案是

listtuple :: [a] -> [(a,a)] 
listtuple (x:y:_) = [(x,y)] 
listtuple _ = [] 

由於您的列表將始終包含一個項目或沒有,所以最好使用Maybe此目的正是服務器。

listtuple2 :: [a] -> Maybe (a,a) 
listtuple2 (x:y:_) = Just (x,y) 
listtuple2 _ = Nothing 
相關問題