StateT с монадой Q из шаблона haskell

Я хотел бы создать функцию, которая принимает некоторые объявления типа Dec (которые я получаю от [d| ... |]) и модифицирую их. Модификации будут зависеть от предыдущих объявлений, поэтому я хотел бы иметь возможность хранить их в карте, скрытой в монаде State - в основном я создаю записи и экземпляры классов и добавляю к ним поля из предыдущих записей. (Таким образом я хочу имитировать ООП, но это, вероятно, не имеет отношения к моему вопросу). Я хотел бы соединить результаты моих вычислений с кодом после того, как я обработаю (и изменю) все объявления.

Я пытался составить StatT с помощью Q всеми возможными способами, но у меня не получается.

Изменить

Моя идея состояла в том, чтобы создать функции, собирающие объявления классов (я знаю, что Haskell не является объектно-ориентированным языком, я читал несколько статей о том, как вы можете кодировать ООП в Haskell, и я пытаюсь реализовать это с помощью Template Haskell как небольшое задание).

Итак, я хотел бы иметь возможность написать что-то вроде этого:

declare [d| class A a where 
                attr1 :: a -> Int
                attr2 :: a -> Int |]
declareInherit [d| class B b where
                      attr3 :: b -> Int |] ''A

Это кодировка (например, код С++)

struct A{
    int attr1;
    int attr2;
}
struct B : A {
    int attr3;
}

И я хотел бы создать две записи с шаблоном haskell:

data A_data = A_data { attr1' :: Int, attr2' :: Int}
data B_data = B_data { attr1'' :: Int, attr2'' :: Int, attr3'' :: Int}

и экземпляры классов:

instance A A_data where
    attr1 = attr1'
    attr2 = attr2'

instance A B_data where
    attr1 = attr1''
    attr2 = attr2''

instance B B_data where
    attr3 = attr3''

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

У меня была проблема с взаимодействием с DecsQ в функции объявления, возможно, я хотел бы, чтобы она существовала примерно так:

data Env = Env {classes :: Map.Map Name Dec }
type QS a = (StateT Env Q) a

У меня также есть проблема, как запустить вычисления в QS.


person kylo_el    schedule 01.06.2014    source источник
comment
Я знаю, что это разочаровывает отсутствие ответа, но вы действительно не хотите имитировать ООП в Haskell, если ваша цель — добиться чего-то продуктивного. Есть аспекты ООП, которые можно продуктивно использовать в Haskell, но то, что вы делаете, не входит в их число.   -  person bitemyapp    schedule 01.06.2014
comment
Вы должны включить код в свой вопрос. Пока неясно, чего вы надеетесь достичь. Q — это монада, но вам не нужно использовать свойства ее монады — вместо этого вы можете просто работать с типами QDec, QExp, QType.   -  person user2407038    schedule 01.06.2014
comment
Вам нужно быть более конкретным. В чем именно проблема, с которой вы столкнулись? StateT сочетается с Q так же хорошо, как и с любой другой монадой.   -  person Nikita Volkov    schedule 01.06.2014


Ответы (2)


Проблема с Template Haskell заключается в том, что его API не так отполирован, как в большинстве других библиотек Haskell. Монада Q перегружена проблемами: она материализует, отображает, управляет состоянием локальных имен. Но никогда не стоит чередовать проблемные области, так как было доказано, что люди могут думать только об одной вещи в каждый момент времени (другими словами, мы «одно ядро»). Это означает, что смешивание проблем вместе не является масштабируемым. Вот почему уже трудно рассуждать о Q, и вы хотите добавить к этому еще одну проблему: ваше состояние. Плохая идея.

Как и к любой другой проблеме, вы должны подходить к этому с разделением интересов. То есть вы должны выделить из основного проблемные домены меньшего размера и работать с каждым из них изолированно. Что касается Template Haskell, то есть несколько очевидных областей: реификация существующих AST, их анализ и рендеринг новых AST. Для связи между этими доменами вам также может понадобиться некоторая модель данных "lingua franca". Что-то напоминает, не так ли? Да, это MVC.

Существуют определенные свойства извлеченных доменов, которые вы можете затем использовать в своих интересах: вам нужно только оставаться в монаде Q для овеществления, рендеринг и анализ могут выполняться в чистой среде, предоставляя вам все ее преимущества. Вы можете безопасно очищать квази-кавычки, используя unsafePerformIO . runQ.

За примерами из жизни я могу сослаться на некоторые из моих проектов, в которых я применяю этот подход:

person Nikita Volkov    schedule 01.06.2014
comment
Экранирование монады Q может быть полезно для меня, но я столкнулся с другой проблемой - если я пытаюсь передать [d| some_declarations |] в функцию, код внутри квазикавычек проверяется (хотя он недоступен) - например, если я создаю экземпляр класса для некоторого типа , тип должен существовать во внешнем коде или в кавычках. Есть ли способ избежать этого? - person kylo_el; 01.06.2014
comment
@kylo_el Все упомянутые определения уже должны присутствовать в контексте. В этом случае, боюсь, вам не избежать Q. Вы должны проверить библиотеку объективов. Они решают одну и ту же задачу в макрос makeClassy. - person Nikita Volkov; 01.06.2014
comment
В прошлый раз, когда я использовал StateT поверх Q, результат был не более запутанным, чем State монада сама по себе, но тогда единственной функцией из Q, которую я использовал в этом контексте, была newName - person Jeremy List; 27.10.2015
comment
Также: пожалуйста, не рекомендуйте unsafePerformIO для этого варианта использования: в монаде Q слишком много функций, которые не работают должным образом при использовании этого подхода. - person Jeremy List; 27.10.2015
comment
@JeremyList Если вы внимательно прочитаете мой вопрос, вы заметите, что я рекомендую использовать эту функцию только для определенной проблемной области, для которой она безопасна. - person Nikita Volkov; 27.10.2015

По крайней мере, в одном файле вы можете передать состояние от одного сплайса DecsQ к другому, расположенному ниже в файле, сохранив его в:

{-# NOINLINE env #-}
env :: IORef Env
env = unsafePerformIO (newIORef (Env mempty))

а затем делать что-то вроде runIO (readIORef env) :: Q Env.

person aavogt    schedule 02.06.2014
comment
На данный момент это лучший способ. Идеальное решение — использовать putQ и getQ, но в getQ была ошибка, которую исправили всего несколько недель назад. - person Jeremy List; 27.10.2015