Объединить список строк, добавив разделитель между ними, используя foldl Haskell - PullRequest
2 голосов
/ 07 ноября 2019

У меня есть функция, которая предназначена для объединения строк в списке, добавления разделителя между ними и вывода одной строки с использованием foldl. Вот то, что у меня есть, и некоторое ожидаемое поведение функции - она ​​не работает, и я не знаю, почему.

-- | `sepConcat sep [s1,...,sn]` returns `s1 ++ sep ++ s2 ++ ... ++ sep ++ sn`
--
-- >>> sepConcat "---" []
-- ""
--
-- >>> sepConcat ", " ["foo", "bar", "baz"]
-- "foo, bar, baz"
--
-- >>> sepConcat "#" ["a","b","c","d","e"]
-- "a#b#c#d#e"

sepConcat :: String -> [String] -> String
sepConcat sep []     = ""
sepConcat sep (x:xs) = foldLeft f base l
  where
    f a x            = a ++ sep ++ x
    base             = ""
    l                = xs

Ответы [ 2 ]

0 голосов
/ 07 ноября 2019

Огромная проблема заключается в сопоставлении вашего шаблона:

sepConcat sep []     = ""
sepConcat sep (x:xs) = foldLeft f base l

Вам не нужно снова делить шаблоны на [] и (x:xs), потому что foldl и foldr позаботьтесь о обоих случаях . Вот как можно определить foldl для списка с рекурсией:

foldLeft :: (b -> a -> b) -> b -> [a] -> b
foldLeft f base []     = base
foldLeft f base (x:xs) = f (foldLeft f base xs) x

вам просто нужно правильно применить оба случая:

sepConcat :: String -> [String] -> String
sepConcat sep xs = foldLeft (\rs s ->
 if null rs 
 then s ++ rs
 else s ++ sep ++ rs) "" xs

Здесь случай пустого списка: "" и функция для рекурсивного случая списка

с вашим примером:

sepConcat ", " ["foo", "bar", "baz"]
=> "foo, bar, baz"
0 голосов
/ 07 ноября 2019

Я думаю, что вы можете решить эту проблему, просто проверив, является ли первый аргумент пустой строкой, и обработайте ее соответственно

sepConcat sep = foldl (\x y -> if x == "" then y else x ++ sep ++ y) ""
-- or
sepConcat sep = foldl combine ""
  where combine "" x = x
        combine x y = x ++ sep ++ y

...