Составление двух функций, вызывающих ошибки, в Haskell - PullRequest
4 голосов
/ 14 января 2010

Проблема, которую мне дали, говорит об этом:

По аналогии с mapMaybe, определить функция: composeMaybe :: (a-> Возможно b) -> (b -> Возможно c) -> (a-> Возможно c) которая состоит из двух функций, вызывающих ошибки.

Тип Maybe a и функция mapMaybe кодируются так:

data Maybe a = Nothing | Just a

mapMaybe g Nothing = Nothing
mapMaybe g (Just x) = Just (g x)

Я пытался использовать композицию так:

composeMaybe f g = f.g

Но он не компилируется.

Может ли кто-нибудь указать мне правильное направление?

Ответы [ 6 ]

7 голосов
/ 14 января 2010

Инструмент, который вы ищете, уже существует. В Control.Monad есть два оператора композиции Клейсли.

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
(<=<) :: Monad m => (b -> m c) -> (a -> m b) -> a -> m c

Когда m = Maybe, реализация composeMaybe становится очевидной:

composeMaybe = (>=>)

Глядя на определение (>=>),

f >=> g     = \x -> f x >>= g

, который вы можете встроить, если вы хотите думать об этом в своих собственных терминах как

composeMaybe f g x = f x >>= g

или который можно записать в do -сахар как:

composeMaybe f g x = do 
    y <- f x
    g y

В общем, я бы просто использовал (>=>), что имеет хорошие теоретические основания для существования, потому что оно обеспечивает самый чистый способ сформулировать законы монады.

6 голосов
/ 14 января 2010

Прежде всего: во всяком случае это должно быть g.f, а не f.g, потому что вам нужна функция, которая принимает тот же аргумент, что и f, и возвращает то же возвращаемое значение, что и g. Однако это не работает, потому что тип возвращаемого значения f не равен типу аргумента g (тип возвращаемого значения f имеет значение Maybe, а тип аргумента g - нет).

Итак, что вам нужно сделать: определить функцию, которая принимает Maybe b в качестве аргумента. Если этот аргумент Nothing, он должен вернуть Nothing. Если аргумент Just b, он должен вернуть g b. composeMaybe должен вернуть композицию функции с f.

5 голосов
/ 14 января 2010

Вот отличное учебное пособие о монадах Haskell (и особенно Возможно, монада , которая используется в первых примерах).

4 голосов
/ 14 января 2010
composeMaybe :: (a -> Maybe b)
             -> (b -> Maybe c)
             -> (a -> Maybe c)
composeMaybe f g = \x ->

Поскольку g принимает аргумент типа b, но f создает значение типа Maybe b, вам необходимо сопоставить шаблон с результатом f x, если вы хотите передать этот результат g.

                         case f x of
                              Nothing -> ...
                              Just y  -> ...
3 голосов
/ 14 января 2010

Очень похожая функция уже существует - оператор монадического связывания, >>=. Его тип (для монады Maybe) - Maybe a -> (a -> Maybe b) -> Maybe b, и он используется так:

Just 100 >>= \n -> Just (show n) -- gives Just "100"

Это не совсем то же самое, что ваша функция composeMaybe, которая принимает функцию, возвращающую значение Maybe вместо прямого значения Maybe для первого аргумента. Но вы можете написать свою composeMaybe функцию очень просто с помощью этого оператора - это почти так же просто, как определение нормальной функции compose, (.) f g x = f (g x).

0 голосов
/ 19 января 2010

Обратите внимание, насколько близки типы аргументов composeMaybe к тому, что оператор монадического связывания хочет для своего последнего аргумента:

ghci> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

Порядок f и g обратен для композиции, так как насчет лучшего названия?

thenMaybe :: (a -> Maybe b) -> (b -> Maybe c) -> (a -> Maybe c) 
thenMaybe f g = (>>= g) . (>>= f) . return

С учетом следующих определений

times3 x = Just $ x * 3

saferecip x
  | x == 0 = Nothing
  | otherwise = Just $ 1 / x

можно, например,

ghci> saferecip `thenMaybe` times3 $ 4
Just 0.75
ghci> saferecip `thenMaybe` times3 $ 8
Just 0.375
ghci> saferecip `thenMaybe` times3 $ 0
Nothing
ghci> times3 `thenMaybe` saferecip $ 0
Nothing
ghci> times3 `thenMaybe` saferecip $ 1
Just 0.3333333333333333
...