Как определить `bind` для типа с синтаксисом записи в Haskell? - PullRequest
1 голос
/ 05 января 2020

Я полностью застрял при решении задания монады в курсе Haskell. Существует пример типа данных, который я хочу определить для Monad-специфицируемых c функций:

data MyMonad a = MyMonad { func :: String -> a }

instance Functor MyMonad where
    fmap f (MyMonad x) = MyMonad (\a -> f (x a))   

instance Applicative MyMonad where
    pure x = MyMonad (\a -> x)
    (MyMonad f) <*> (MyMonad g) = MyMonad (\a -> (f a)(g a))

instance Monad MyMonad where
    return x = MyMonad (\a -> x)
    MyMonad x >>= f = f (\a -> x a) --my wrong definition 

После объявления экземпляров Functor и Applicative я пытаюсь сделать то же самое для Monad, но ... Я немного ближе к пониманию того, как вписать синтаксис записи func в эту функцию f. До сих пор я вижу bind как функцию, принимающую x из MyMonad перед отображением его на f. Насколько я понимаю, это просто важная особенность любой монады - позволяет помещать некоторые значения из одного контекста типа данных в другой. Если честно, мне известны bind определения в экземплярах Monad для [a], Maybe и некоторых других вездесущих типах. Да, я ясно вижу, для чего служит класс Монады. Тем не менее, мне нужно получить какое-либо предложение в этом конкретном случае c только для того, чтобы улучшить мое понимание того, как иметь дело с чем-то вроде записей.

1 Ответ

0 голосов
/ 05 января 2020

x в MyMonad x имеет тип String -> a, в то время как f имеет тип a -> MyMonad b, поэтому мы должны вернуть MyMonad b (который включает функцию String -> b).

Таким образом, мы должны сконструировать функцию, которая отображает s :: String в b. Мы можем сделать это, сначала передав s функции x, и получив значение типа a. Затем мы мы можем вызвать f с a в качестве этого параметра и получить MyMonad g. Затем мы можем применить это s к g.

Таким образом, мы можем реализовать экземпляр Monad следующим образом:

instance Monad MyMonad where
    return x = MyMonad (\a -> x)
    MyMonad x >>= f = MyMonad (<b>\s -> let MyMonad g = f (x s) in g s</b>)

, так как вы определили "getter" func :: MyMonad a -> a -> String, мы можем использовать этот getter вместо использования выражения let &hellip; in &hellip; для "разворачивания" значения из конструктора данных MyMonad:

instance Monad MyMonad where
    return x = MyMonad (\a -> x)
    MyMonad x >>= f = MyMonad (<b>\s -> func (f (x s)) s</b>)
...