Шаблон Haskell, соответствующий первому, среднему разделу и последнему - PullRequest
8 голосов
/ 22 марта 2012

Итак, я хотел сделать простую функцию обращения строк в Haskell

swapReverse :: String => String  
swapReverse [x] = [x]
swapReverse [x,y] = [y,x]
swapReverse (x:xs:l) =         -- pattern match fails here 
  let last = [l]
      middle = xs
      first = [x]
  in  last ++ swapReverse middle ++ first

Так есть ли способ определения структуры шаблона в haskell, который имеет элемент first и last, и все элементы в middle?

Ответы [ 4 ]

6 голосов
/ 22 марта 2012

Нет, вы не можете. Зачем? Потому что шаблон соответствует значениям соответствия и их частям, но «середина» списка не является частью списка. Список [1, 2, 3, 4] равен 1:(2:(3:(4:[]))), с точки зрения его структуры. Таким образом, вы хотите сопоставить first с 1 и last с 4, которые являются частями списка и, таким образом, не дисквалифицированы. Но желаемым middle будет 2:(3:[]), который не является частью списка и, следовательно, не может быть совпадением.

Обратите внимание, что мы также не можем написать шаблон для совпадения с первым и последним элементами списка одновременно. У шаблона есть глубина, которая фиксируется во время компиляции.

5 голосов
/ 22 марта 2012

Сопоставление с образцом работает на конструкторах, : - единственный конструктор списка, поэтому вы не можете найти соответствие в середине списка. Вам нужно создать новый список задом наперед (очевидно, :)), что можно сделать, взяв голову и добавив ее к обратной стороне остального списка.

1 голос
/ 22 марта 2012

Попробуйте этот код:

last1 (x:xs:l) = (x,xs,l)

l не дает вам последний элемент в списке, он получает вас от остальной части списка, кроме первых двух переменных, которым назначены первые два элемента в списке.

Когда вы пишете совпадение с шаблоном для списка, первой переменной назначается первый элемент и так далее, пока программа не доберется до последней переменной, где ей будет присвоено все оставшееся. Нет ничего особенного в добавлении s после x, переменная с именем y будет делать то же самое.

Если вы хотите получить последний элемент списка, вам нужно создать шаблон, подобный (x:xs), и использовать рекурсию на xs и применять этот шаблон, пока вы не перейдете к одному элементу списка, который является последний элемент. Тем не менее, я бы порекомендовал прочитать ответ Адама Бергмарка , чтобы лучше перевернуть список, не включая поиск первого и последнего элементов списка.

0 голосов
/ 22 марта 2012

Рабочая версия:

swapReverse :: String -> String  
swapReverse (x:xs) = [last xs] ++ swapReverse (init xs) ++ [x]
swapReverse xs = xs

Обратите внимание, что эта реализация является катастрофой с точки зрения производительности. Реализации, использующие складку и / или аккумуляторы, гораздо более эффективны.

...