#string #list #haskell #fold
Вопрос:
Создайте функцию, которая берет строку и разбивает ее на список кортежей типа
(word, length word)
. Это нужно сделать, используяfoldr
один проход списка, без использованияlength
и/или( )
.Например
gt; splitSen " Asdf qw zx mn " [("Asdf",4),("qw",2),("zx",2),("mn",2)]
Моя реализация выглядит так
splitSen :: String -gt; [(String,Int)] splitSen cs = foldr func [] cs where func ' ' ((c1,n1) : ps) = ps func c ((c1,n1) : ps) = (c:c1,1 n1):ps
И я получаю ошибку
*** Исключение: неисчерпывающие шаблоны в функциях func
Но не могу понять, какой шаблон мне не хватает.
Ответ №1:
Давайте включим предупреждения! Это можно сделать с -Wall
помощью флага.
$ ghci -Wall gt; :{ | splitSen :: String -gt; [(String,Int)] | splitSen cs = foldr func [] cs where | func ' ' ((c1,n1) : ps) = ps | func c ((c1,n1) : ps) = (c:c1,1 n1):ps | :} lt;interactivegt;:6:3: warning: [-Wincomplete-patterns] Pattern match(es) are non-exhaustive In an equation for ‘func’: Patterns not matched: p [] where p is not one of {' '} ' ' [] lt;interactivegt;:6:14: warning: [-Wunused-matches] Defined but not used: ‘c1’ lt;interactivegt;:6:17: warning: [-Wunused-matches] Defined but not used: ‘n1’
Выше предупреждение сообщает, что случай с пустым списком []
не обрабатывается func
.
Комментарии:
1. это правда, но теперь я также вижу, что вся моя функция неверна.
2. @BohdanChornopolskyi Я не много думал о том, как это решить, но, скорее всего, вам нужно использовать более сложный «накопитель», чем просто список конечных результатов. Возможно, вам нужна пара, содержащая 1) ваш список и 2) логическое значение, указывающее, начинается ли следующее не-пробел со своего собственного слова, чтобы каким-то образом отслеживать пробелы. После
foldr
этого вы можете выбросить логическое значение сfst
помощью . Этот метод такой же, как и в вашем предыдущем вопросе: создайте кортеж с дополнительной информацией для сгиба и отбросьте половину в конце.
Ответ №2:
На случай, если у кого-нибудь когда-нибудь появится что-то подобное здесь, что мне удалось сделать
splitSen = fst . foldr func ([], True) where func ' ' ([], _) = ([], True) func c ([],bool) | bool = ([([c],1)], False) func ' ' (((word, len):rest), bool) = (((word, len):rest), True) func c (y@((word, len):rest), bool) | bool = (([c],1):y, False) | otherwise = (((c:word, 1 len):rest), False)
Выглядит очень плохо, но работает…