2013-02-11 2 views
3

Удивление, если я смогу получить помощь в написании этой функции. Я пытаюсь создать функцию, которая инвертирует каждую «пару» в списке.Haskell Invert Pair

module Invert where 
invert :: [(a,b)] -> [(b,a)] 
invert [(a,b)] = [(b,a)] 

Когда я вхожу invert [(3,1) (4,1) (5,1)] ... он должен дать мне [(1,3) (1,4) (1,5) ... Но это дает мне ...


*Invert> [(3,1) (4,1) (5,1)] 

<interactive>:2:2: 
    The function `(3, 1)' is applied to two arguments, 
    but its type `(t0, t1)' has none 
    In the expression: (3, 1) (4, 1) (5, 1) 
    In the expression: [(3, 1) (4, 1) (5, 1)] 
    In an equation for `it': it = [(3, 1) (4, 1) (5, 1)] 
+0

Забыл запятые лол ... но она по-прежнему дает мне «неисчерпывающие модели в функции инвертировании» –

ответ

14

Поскольку списки являются рекурсивными структурами данных, вам необходимо обработать список рекурсивно, чтобы поменять местами все его элементы или использовать некоторую функцию более высокого порядка, которая выполняет обработку для вас. Если вы определяете

invert [(a,b)] = [(b,a)] 

он преобразует только одноэлементные списки, все другие входы с ошибкой будут сбой!

Постарайтесь думать о вводе invert получает: это либо пустой список, либо непустые списки. В случае непустого списка вы можете поменять первый элемент и преобразовать остальное рекурсивно.

(Если вы не хотите, чтобы инвертировать invert себя, просто используйте

invert = map swap 

где swap составляет от Data.Tuple.)

+0

Спасибо, я понял! Я закончил использование явной рекурсии :) –

+1

Чтобы прояснить для других людей, когда вы пишете 'invert [(a, b)] = [(b, a)]', вы действительно записываете 'invert ((a, b): []) = (b, a): [] ', поэтому эта функция работает только в списках одного элемента. Это частый источник путаницы для начинающих. –

3

Итак, вы хотите, чтобы отобразить функции по список типа (a, b) -> (b, a). Функция (,) имеет тип b -> a -> (b,a). Поэтому, если мы перевернем его, получим a -> b -> (b, a). Теперь, если мы uncurry что, мы получаем (a, b) -> (b, a):

invert = map (uncurry $ flip (,)) 

Э.Г.

> map (uncurry $ flip (,)) [(1, "a"), (2, "b")] 
[("a",1),("b",2)] 

Как в стороне, ваше соответствие patten не соответствует тому, что вы хотите. Определение

invert [(a,b)] = [(b,a)] 

говорит «сопрягать список с одним кортежем в нем». Если у вас есть список с несколькими кортежами, совпадение не будет выполнено. Кроме того, как указал Джош Ли, вам нужно запятую между кортежами в вашем списке.

+5

Гораздо более сжато написано как «своп карты». –

4

Лучший способ решить эту проблему: разбить его на более мелкие проблемы, а также найти библиотечные функции, которые решают эти проблемы, или написать свои собственные. Я всегда говорю новичкам, что это выше упражнение, чем пытаться написать функцию, как invert всего одна часть, потому что вы должны учиться следующие три вещи:

  1. Как разбить проблему на мелкие, многоразовые куски.
  2. Стандартные функции библиотеки, предлагаемые языком.
  3. Как использовать рекурсию для записи небольших, многоразовых функций, таких как те, которые содержатся в стандартной библиотеке.

В этом случае мы можем разделить проблему на:

  1. Инверсия индивидуальный кортеж.
  2. Применение функции ко всем элементам списка и сбор списка результатов.

Вторым является только обычная функция map в списках, которая поставляется со стандартной библиотекой. Вы можете попробовать написать свою собственную версию; такого рода вещи всегда хорошее упражнение для начинающих:

map :: (a -> b) -> [a] -> [b] 
map f []  = ... 
map f (x:xs) = ... 

Первый, как и Петр указывает, является swap функция от Data.Tuple. Но мы можем написать наши собственные легко:

swap :: (a, b) -> (b, a) 
swap (a, b) = (b, a) 

И теперь, конечно:

invert :: [(a, b)] -> [(b, a)] 
invert = map swap