Обессахаривание до-нотации для монад

Изучая Haskell, я понимаю, что нотация do - это просто синтаксический сахар:

a = do x <- [3..4]
       [1..2]
       return (x, 42)

Переводится в

a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42)))

Я понимаю, что, вероятно, буду использовать нотацию do, но я хотел бы понять, что происходит при переводе. Так что чисто из педагогических соображений, есть ли способ для ghc / ghci предоставить мне соответствующие операторы связывания для довольно сложной монады, написанной в do-notation?

Edit. Оказывается, lambdabot на #haskell может это сделать:

 @undo do x <- [3..4] ; [1..2] ; return (x, 42)
 [3 .. 4] >>= \ x -> [1 .. 2] >> return (x, 42)

Вот исходный код Плагин отмены .

24
задан Stephen Diehl 6 November 2011 в 11:07
поделиться

1 ответ

Вы можете запросить вывод десугарера GHC, однако это также приведет к десагару многих других синтаксисов.

Во-первых, мы поместим ваш код в модуль Foo.hs:

module Foo where

a = do x <- [3..4]
       [1..2]
       return (x, 42)

Далее, мы попросим GHC скомпилировать его и вывести результат после фазы отладки:

$ ghc -c Foo.hs -ddump-ds

Вывод может выглядеть довольно грязно, потому что это вариант Haskell, называемый Core, который используется в качестве промежуточного языка GHC. Тем не менее, это не слишком сложно читать, когда вы привыкнете к нему. В середине некоторых других определений мы находим ваше:

Foo.a :: [(GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)]
LclIdX
[]
Foo.a =
  >>=_agg
    @ GHC.Integer.Type.Integer
    @ (GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)
    (enumFromTo_ag7
       (GHC.Integer.smallInteger 3) (GHC.Integer.smallInteger 4))
    (\ (x_adf :: GHC.Integer.Type.Integer) ->
       >>_agn
         @ GHC.Integer.Type.Integer
         @ (GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)
         (enumFromTo_ags
            (GHC.Integer.smallInteger 1) (GHC.Integer.smallInteger 2))
         (return_aki
            @ (GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)
            (x_adf, GHC.Integer.smallInteger 42)))

Ядро не слишком красивое, но возможность читать его очень полезно при работе с GHC, так как вы можете прочитать дамп после последующих этапов. чтобы увидеть, как GHC оптимизирует ваш код.

Если мы удалим суффиксы _xyz, добавленные переименователем, а также приложения типа @ Xyz и вызовы GHC.Integer.smallInteger, и снова сделаем операторы инфиксными, у вас останется нечто вроде этого:

Foo.a :: [(GHC.Integer.Type.Integer, GHC.Integer.Type.Integer)]
Foo.a = enumFromTo 3 4 >>= \x -> enumFromTo 1 2 >> return (x, 42)
20
ответ дан 29 November 2019 в 00:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: