Как объявить функцию (недопонимание типа Может быть)

Мне нужна функция, которая работает так:

some :: (Int, Maybe Int) -> Int
some a b
     | b == Nothing = 0
     | otherwise = a + b

Случаи применения:

some (2,Just 1)
some (3,Nothing)
map some [(2, Just 1), (3,Nothing)]

Но мой код вызывает ошибку:

The equation(s) for `some' have two arguments,
but its type `(Int, Maybe Int) -> Int' has only one

Я этого не понимаю.

Заранее спасибо.


person demas    schedule 06.12.2010    source источник
comment
Возможно, вас заинтересует более общий вопрос о том, как работать с типом Maybe a, ответил здесь.   -  person Thomas M. DuBuisson    schedule 07.12.2010


Ответы (2)


Когда ты пишешь

foo x y = ...

Это обозначение для функции каррированной с таким типом, как:

foo :: a -> b -> c

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

some :: (Int, Maybe Int) -> Int
some (x, y) = ...

Но соглашение Haskell обычно принимает аргументы в прежней каррированной форме. Очень редко можно увидеть, как функции принимают кортежи в качестве аргументов.

Что касается другой части вашего вопроса, вы, вероятно, захотите выразить это с помощью сопоставления с образцом. Ты мог бы сказать:

foo :: Maybe Int -> Int
foo Nothing = 0
foo (Just x) = x + 1

Обобщая это на вопрос ОП, оставляем читателю в качестве упражнения.

person luqui    schedule 06.12.2010
comment
Спасибо. Мне нужно сопоставление с образцом. - person demas; 06.12.2010
comment
Вместо сопоставления с образцом я бы, вероятно, написал это some a b = fromMaybe 0 (fmap (+ a) b) и без точек до some a = fromMaybe 0 . fmap (+ a). - person John L; 06.12.2010
comment
@John, как вы думаете, полезно ли предлагать использование функторов и бесточечный стиль тем, кто еще не разбирается в каррировании и сопоставлении с образцом? - person adamse; 08.12.2010

Ваша ошибка возникла не из-за неправильного понимания Maybe: подпись типа some указывает, что он принимает пару (Int, Maybe Int), тогда как в вашем определении вы предоставляете ему два аргумента. Таким образом, определение должно начинаться с some (a,b), чтобы соответствовать сигнатуре типа.

Один из способов решить проблему (который также немного более идиоматичен и использует сопоставление с образцом):

some :: (Int, Maybe Int) -> Int
some (a, Nothing) = a
some (a, Just b) = a + b

Также стоит отметить, что, если у вас нет действительно веской причины для использования кортежа в качестве входных данных, вам, вероятно, не следует этого делать. Если бы ваша подпись была вместо some :: Int -> Maybe Int -> Int, у вас была бы функция двух аргументов, которые могут быть каррированными . Тогда вы бы написали что-то вроде

some :: Int -> Maybe Int -> Int
some a Nothing = a
some a (Just b) = a + b

Кроме того, вы можете добавить следующее немедленное обобщение: все типы Num аддитивны, так что вы можете также сделать

some :: (Num n) => n -> Maybe n -> n
some a Nothing = a
some a (Just b) = a + b

(Я нарушил обычную практику использования a, b, c ... для переменных типа, чтобы не путать OP, поскольку он связывает a и b с аргументами some).

person gspr    schedule 06.12.2010