Создайте функцию, которая берет строку (некоторое предложение) и разбивает ее на список кортежей (слово, длина слова).

#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)  

Выглядит очень плохо, но работает…