2015-10-26 5 views
0

У меня есть код, как это:Haskell рекурсии в списках

appd (a:e) ((c,b):bs) | a == c && bs /= [] = b:appd(a:e) bs 
         | a /= c && bs /= [] = appd (a:e) bs 
         | a /= c && bs == [] = appd e ((c,b):bs) 
         | otherwise   = b:appd e ((c,b):bs) 

Это петли повсеместно в два списка, как [1,2,3] и [(1,2),(6,5),(3,5)] и принимает первый элемент из первого списка и сравнивает его с первым элементом каждого кортежа в другом списке , если они равны, то сохраните второй элемент этого кортежа. Он отлично работает, но сравнение не работает, если я беру второй элемент первого списка, в данном случае 2.

Например, если у меня есть списки, как [1,2,3] и [(1,2),(6,5),(3,5)], то функция принимает 1 из первого списка и сравнивает с 1, затем 6, затем 3, что работает, но он не принимает второй элемент первого списка - 2 и не повторяет сравнение. Что не так?

+0

Не удалось воспроизвести: в моих тестах он действительно возвращает результаты в сочетании с '1',' 2' и '3'; например, 'appd [1,2,3] [(1,2), (6,5), (3,5)]', как представляется, правильно возвращает как '2' из' (1,2) ', так и '5' из' (3,5) 'перед сбоем. Если я добавлю '(2,4)' в конце, он вернет '4' перед сбоем. Однако эта функция плохо частичная - она ​​в конечном счете падает почти на каждом входе. Возможно, если вы исправите это (попробуйте проверить вывод GHC на '-fwarn-incomplete-patterns'), он будет вести себя так же, как вы этого хотите. –

+0

Способ ответа на ваш вопрос состоит в том, чтобы взять тестовый пример, который вы выделили ('appd [1,2,3] [(1,2), (6,5), (3,5)]') и внимательно следите за его исполнением в своей голове, на бумаге или с отладчиком, и тщательно размышляйте. – jberryman

+0

Я пробовал, но не вижу ошибки – dreamPr

ответ

1

Прежде всего, позвольте мне заметить, что вы должны были включить сообщение об ошибке, которое вы получали. Вы также должны показать нам примерный выход и выборки.


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

appd _  []   = [] 
appd [] bs   = snd <$> bs -- you can decide to use [] instead 
appd (a:e) ((c,b):bs) 
    | a == c && bs /= [] = b:appd(a:e) bs 
    | a /= c && bs /= [] = appd (a:e) bs 
    | a /= c && bs == [] = appd e ((c,b):bs) 
    | otherwise   = b:appd e ((c,b):bs) 

теперь ваша функция работает на входе вы при условии, но я не уверен, что он возвращает результаты, которые вы желаете:

*Main> appd [1,2,3] [(1,2),(6,5),(3,5)] 
[2,5,5] 

Кроме, я очищено ваш код немного и аннотированный вашу функцию с явной сигнатуры типа:

appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b] 
appd []   bs  = snd <$> bs 
appd _   []  = [] 
appd [email protected](a:ass) [email protected]((c,b):bss) 
    | a == c && bss /= [] = b : appd as bss 
    | a /= c && bss /= [] =  appd as bss 
    | a /= c && bss == [] =  appd ass bs 
    | otherwise   = b : appd ass bs 

Также, вы можете использовать более простую, нерекурсивную реализацию в получить те же результаты, что и выше:

appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b] 
appd as bs = snd <$> filter (\(a,_) -> a `elem` as) bs 

или если вы хотите point free (ака tacit):

appd :: (Eq a, Eq b) => [a] -> [(a,b)] -> [b] 
appd as = (snd <$>) . filter ((`elem` as) . fst) 

Примечание:<$> является псевдонимом для fmap, который, в свою очередь, ведет себя так же, как map при использовании в списках.

+1

https://www.haskell.org/hoogle/?hoogle=%3C % 24% 3E –

+0

ах, да, я забыл упомянуть, что '<$>' делает. –

+0

Спасибо вам большое! К сожалению, моя функция по-прежнему не работает даже с вложениями, но ваша упрощенная реализация работает отлично. Здесь вводится образец: [1,2,3,4] [(1,5), (3,8), (5,5), (4,3), (2,9)] выход: [5, 9,8,3] – dreamPr

Смежные вопросы