Использование возможно для сопоставления шаблонов списка отображает ошибку

Как мне использовать конструктор Just при декомпозиции паттерна?
НАПРИМЕР:
Если мой шаблон: (x1,x2,x3,....xn), мне нужно будет заключить каждый элемент шаблона в его Just?

Моя проблема : Я пытаюсь реализовать функцию Init "безопасно" .
Должен ли я использовать Just для хвоста и для головы во второй строке?

safeInit::[a]->Maybe [a]
safeInit (x:xs)=x: safeInit (Just xs) #Just x : safeInit Just xs ?
safeInit [x,y]=Just [x]
safeInit _ =Nothing

Используйте safeInit (x:xs) = Just (init (x:xs)).

Elmex80s 11.04.2018 14:22
0
1
44
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Здесь есть две проблемы:

  • вы совершаете звонок с Maybe [a] на входе; а также
  • ваш первый шаблон содержит (строгий) надмножество, затем второй, поэтому второй будет срабатывать никогда.

По первой проблеме виноват в строке:

safeInit (x:xs) = x: safeInit (Just xs)

Здесь safeInit ожидает список (тип [a]), но вы обертываете список в конструкторе Just, поэтому вы передаете ему значение Maybe [a], и safeInit не может с этим справиться. Итак, мы можем переписать его так:

safeInit (x:xs) = x : safeInit xs

Однако это решит проблему нет, поскольку теперь мы вызываем «минусы» (:) на a и Maybe [a], и снова функция не может справиться с этим. Сначала нам нужно будет проверить, создает ли рекурсивный вызов safeInit, а затем добавить x и заново обернуть его в Just, мы можем сделать это с помощью fmap:

safeInit (x:xs) = fmap (x:) (safeInit xs)

Для второй проблемы мы можем переставить предложения:

safeInit :: [a] -> Maybe a
safeInit [x, _] = Just [x]
safeInit (x:xs) = fmap (x:) (safeInit xs)
safeInit [] = Nothing

Тем не менее, с этим подходом все еще есть проблемы: он довольно неэффективен, поскольку мы разворачиваем и оборачиваем элемент Just для всех элементов (кроме последнего), если он не оптимизирован. Более того, если мы обработаем бесконечный список, мы застрянем в бесконечном цикле. Мы можем улучшить его, используя внутреннюю функцию, которая вычисляет init, если мы точно знаем, что этот init действителен. Например:

safeInit :: [a] -> Maybe a
safeInit (x:xs) = Just (go x xs)
    where go _ [] = []
          go x (x2:xs) = x : go x2 xs
safeInit [] = Nothing

Но разве вы не меняете таким образом исходный список?

Bercovici Adrian 11.04.2018 14:43

@BercoviciAdrian: в Haskell ничего нельзя изменить, все переменные неизменяемы. Как вы думаете, каким образом я изменяю первоначальный список?

Willem Van Onsem 11.04.2018 14:43

Нет, вы не изменяете, я думал, вы добавляете x к xs ... вы просто разлагались дальше с помощью «x2». Мне очень жаль.

Bercovici Adrian 11.04.2018 14:48

Ну, это зависит от того, какую семантику вы хотите. В случае init, если вы вообще нашли какой-либо элемент, вы знаете, что в любом случае результатом будет Just, а именно Just init_xs. Затем вы хотите добавить текущий x в список включенных, ничего не меняя в Just. Самый простой способ сделать это - использовать экземпляр MaybeFunctor:

safeInit (x:xs) = (x:) <$> safeInit xs

Однако обратите внимание, что это работает только в том случае, если вы добавляете дополнительный базовый случай, и предложение должно быть перед общим cons:

safeInit :: [a] -> Maybe [a]
safeInit [_] = Just []
safeInit (x:xs) = (x:) <$> safeInit xs
safeInit []  = Nothing

Альтернативой, которая, возможно, легче понять, является сопоставление с образцом рекурсивного результата:

safeInit (x:xs) = case safeInit xs of
      Just init_xs -> Just $ x : init_xs
      Nothing -> Just []
safeInit [] = Nothing

Расширяя предложение Elmex80s,

safeInit :: [a] -> Maybe [a]
safeInit [] = Nothing
safeInit xs = Just (init xs)

Я не хотел использовать нестандартные методы, но все равно спасибо.

Bercovici Adrian 11.04.2018 14:42

Другие вопросы по теме