2016-09-15 60 views
0

我是新來的Haskell,並試圖實現一個功能,需要一個分離器和一個列表,返回一個連接字符串(類似於加入功能在Python)實現字符串連接功能在Haskell

strJoin sep arr = case arr of 
    [] -> "" 
    (x : xs) -> x ++ sep ++ strJoin sep xs 

當我調用此函數strJoin "|" ["foo", "bar"]它打印"foo|bar|"即使我想結果看"foo|bar"

我如何調整我的模式匹配代碼,以便它最後一個元素不同的方式工作?

回答

4

的問題是在你的代碼的最後一行:

(x : xs) -> x ++ sep ++ strJoin sep xs 

模式x : xs的含義是x將匹配一個元素,即列表的第一個元素,xs將匹配列表,即除第一個元素外的所有元素的列表。該列表可以是空的。具體而言,如果arr包含單個元素,則x將與該單個元素匹配,並且xs將與列表的其餘部分匹配,該列表是空列表。但隨後,在右手邊的,這樣就:

x ++ sep ++ strJoin sep [] 

這相當於

x ++ sep ++ "" 

這又是一樣的

x ++ sep 

這解釋的行爲你的功能。那麼我們如何解決這個問題呢?一種解決方案是嘗試更改該案例的模式,以便該規則不會在具有單個元素的列表上使用。要做到這一點的方法之一是,像這樣:

(x : xs @ (_ : _)) -> x ++ sep ++ strJoin sep xs 

這裏xs @ (_ : _)將匹配一個非空列表。我將把這個解釋作爲一個練習。 因此,現在該規則不會用於單個元素列表,因爲我們想要,但問題是沒有這樣的列表的規則了。所以我們需要添加一個新的。下面將做:

[x] -> x 

所以把他們放在一起:

strJoin sep arr = case arr of 
    [] -> "" 
    (x : xs @ (_ : _)) -> x ++ sep ++ strJoin sep xs 
    [x] -> x 

當然還有很多其他的方法可以做到這一點,這裏有一個:

strJoin sep arr = case arr of 
    [] -> "" 
    [x] -> x 
    (x : xs) -> x ++ sep ++ strJoin sep xs 

我會離開它作爲一個練習如何運作。

+0

感謝您回答這個問題。我第一次看到@,我會找到解釋它是如何工作的。順便說一句你的第二個解決方案更具可讀 – Raj

3

您的解決方案的問題在於第二種模式也可以匹配具有一個元素的元素(在這種情況下xs[]),因此您將有一個額外的遞歸調用。

strJoin sep arr = case arr of 
    [] -> "" 
    ([x]) -> x 
    (x : xs) -> x ++ sep ++ strJoin sep xs 

如果你不希望建立這個自己學習之用,Data.Listintercalate爲了這個目的:

https://www.haskell.org/hoogle/?hoogle=intercalate

import Data.List 

intercalate "|" ["foo", "bar"] 

或者你可以使用concatintersperse在一起。

+0

感謝您的回答。我很想知道這是否可以使用模式匹配來完成。 – Raj

+0

我給你加了一個答案。 –

+3

@Raj一切都是使用模式匹配完成的。 –