Использовать нотацию без монад: возможно?

У меня есть тип с отслеживанием состояния с >> и >> = , что является почти монадой. Предполагаемое использование - создание кода для другого языка, и наличие доступной нотации будет очень уместным.

Однако нет четко определенной функции возврата, так как значения должны производиться только вместе с побочными эффектами . Итак, если я подделываю функцию возврата, функция возврата должна возвращать только ошибку и нарушает законы монад. (То есть никогда нельзя использовать функцию возврата.)

Я заметил, что в нотации do используются только два оператора: >> и >> = . .

Есть ли способ сохранить что-то вроде нотации do только для этих двух операторов или что-то столь же чистое, но без создания монады?

ПРИМЕЧАНИЕ: Ниже строки приведены детали, которые не являются необходимыми для вопрос в заголовке. Это контекст того, почему я задал этот вопрос, ответы на которые меня интересуют. Другие, просматривающие эту тему, вероятно, предпочтут проигнорировать ее.


ИСПРАВЛЕНИЕ: Я не генерирую код на императивном языке, хотя и не должен не имеет значения. Я генерирую код в Javascript.

УТОЧНЕНИЕ (в ответ на bdonlan): Мой тип - (ma), который передает состояние (то есть код, который должен быть сгенерирован при различных параметрах, аналогично монаде состояний) и будет вернуть значение (имена переменных в сгенерированном коде с прикрепленным типом haskell). Таким образом, не должно быть способа вернуть значения, связанные с именами переменных, без генерации кода, определяющего имена переменных. * Это исключительно из-за моего дизайна, который может быть хуже других, о которых я не думал.

В ответ на ответы: Кажется, есть два типа ответов на это. Во-первых, это действительно возможно и, возможно, лучший способ использовать нотацию do. Второй вопрос заключается в том, лучше ли использовать монаду и определять возврат (или имеет смысл вообще этого не делать - возможно, позже я обнаружу, что требуется возврат).

Пример того, что я буду делать:

data JsState = JsState { code :: String , vidCount :: Int } 
-- vidCount is for generating unique variable names

newtype JsStmt = JsStmt ( JsState -> JsState )

newtype JsMonad a = JsMonad ( JsState -> ( a , JsState ) )

def :: (JsValue a) => a -> JsMonad a

-- Outputs "var " ++ toUniqueVarName vidCount ++ " = " toCode a ++ ";"

-- Returns JsMonad with the variable name as the value,
-- with a type attached, and the JsState's vidCount is incremented by 1.


alertJsInt :: JsIntE -> JsMonad ()

-- Outputs something like "alert(" ++ toCode JsIntE ++ ");"

do
  x <- def $ JsIntL 2
  y <- def $ JsIntL 4
  alertJsInt (x + y)
23
задан HaskellElephant 22 June 2011 в 08:39
поделиться

2 ответа

Ну, структура, с которой вы работаете, уже существует; Соответствующий класс типов можно найти в Hackage , на самом деле. Тем не менее, я не рекомендую пытаться навязать это в Monad по причинам, указанным bdonlan. Существование return довольно фундаментально, и вы, вероятно, везде будете сталкиваться с проблемами, пытаясь использовать стандартные функции для Monad с.

.... однако! Тем не менее, если вы действительно хотите do нотацию, рассмотрите эту цитату из руководства пользователя GHC :

Нотация «Do» переводится с использованием любых функции (>> =), (>>) и сбой находятся в области видимости (не версии Prelude).

... другими словами, вы правы в том, что использование нотации do имеет смысл, потому что нигде не используется return при десагарации. Этот раздел о расширении RebindableSyntax, которое делает именно то, что заявляет. Если вы не возражаете отказаться от нотации do для Monad, вы можете использовать это расширение, определить свои собственные функции и использовать нотацию do все, что вам нравится.

21
ответ дан 29 November 2019 в 01:57
поделиться

Похоже, у вас есть стрелка . В монаде вы должны быть в состоянии написать:

do
   x <- return $ f y
   if x then something else notSomething

Условие «если» оценивается как часть оценки «делать», и в результате получается либо «что-то», либо «не так» , но не оба сразу. Однако для генерации кода вы, вероятно, захотите, чтобы «если» было преобразовано в ваш сгенерированный код с оценкой обеих ветвей, чтобы создать код, который может сделать выбор во время выполнения.

Эквивалентный код для стрелки приводит к использованию класса ArrowChoice, в котором у вас есть доступ как к условию, так и к обеим ветвям, что вам и нужно.

4
ответ дан 29 November 2019 в 01:57
поделиться