Есть ли способ «поднять» конструктор? - PullRequest
0 голосов
/ 20 марта 2019

Предположим, у меня есть функция (plusOne в приведенном ниже примере), которая принимает и возвращает только Int.Но у меня нет Int;вместо этого у меня есть Maybe Int;и если это Maybe Int содержит значение, то я хочу передать его plusOne и получить Just того, что plusOne возвращает, или, если это скорее Nothing, тогда я хочу, чтобы этот Nothing распространялся.

В таком случае у нас есть liftM для элегантного кодирования:

import Control.Monad

plusOne :: Int -> Int
plusOne n =
    n+1 -- a very complicated computation that is failsafe

main =
    let n = Just 15 -- a very complicated computation that can fail
    in let res = liftM plusOne n
    in print res

Пока все хорошо.Но можно ли что-то подобное сделать и с конструкторами?

Забудьте о plusOne.Теперь у меня есть: data SomeData = SomeData Int и я хочу получить Maybe (SomeData Int) из моего Maybe Int.Решение кажется заметно менее элегантным:

import Control.Monad

data SomeData = SomeData Int
    deriving Show -- so that print works

main =
    let n = Just 15
    in let res = n >>= (\nn -> Just (SomeData nn))
    -- alternatively: in let res = liftM (\nn -> SomeData nn) n
    in print res

Оба вышеупомянутых решения (с >>= или с liftM) требуют прохождения анонимной лямбда-функции, которая, на мой взгляд, не должна быть необходимой и толькослужит для того, чтобы заглушить код.Есть ли способ избежать этого?Можно ли как-то «поднять» конструктор someData так же, как я мог бы поднять plusOne в первом фрагменте?

1 Ответ

4 голосов
/ 20 марта 2019

Вы можете просто использовать композицию функций:

main =
    let n = Just 15
        res = n >>= Just . SomeData
    in print res

хотя, как указывает Робин Зигмонд, вы можете просто использовать fmap, поскольку fmap f x эквивалентно x >>= return . f и return == Just для монады Maybe.

main = let n = Just 15
           res = fmap SomeData n  -- or SomeData <$> n
       in print res

Мораль истории: не используйте монаду, где все, что вам нужно, это функтор.

...