брейнфака. У меня есть функция run которая делает пошаговое исполнение операций.
type Interrupt r a = ProgramState a -- ^ state of interpreter at the moment of interrupt
-> (ProgramState a -> Cont r (ProgramState a)) -- ^ return continuation
-> Cont r (ProgramState a)
-- step by step interpretation of the program from the given 'ProgramState a'
run :: (Num a, Ord a, Eq a) => ProgramState a
-> Interrupt r a -- ^ Print interrupt
-> Interrupt r a -- ^ Write interrupt
-> Cont r (ProgramState a)
run ps printI writeI = let code = getCode ps in
case currentInstruction $ getCode ps of
MoveCell n -> return . setCode (shiftRCode code) $ move (fromIntegral n) ps
ChangeCell n -> return . setCode (shiftRCode code) $ change (fromIntegral n) ps
PrintCell -> do
ps' <- callCC $ \ret -> printI ps ret
return $ setCode (shiftRCode code) ps'
WriteCell -> do
ps' <- callCC $ \ret -> writeI ps ret
return $ setCode (shiftRCode code) ps'
LoopL -> let Memory {..} = getMemory ps
code = getCode ps
in case current of
0 -> return $ seekLoopR ps
_ -> return . flip setCode ps $ shiftRCode code
LoopR -> let Memory {..} = getMemory ps
code = getCode ps
in case current of
0 -> return . flip setCode ps $ shiftRCode code
_ -> return $ seekLoopL ps
End -> return ps
Проблема заключается в том, что я не хочу привносить в нее еффекты только ради двух операторов (WriteCell и PrintCell), так как 80% этой функции абсолютно "чисты". Моя идея для решении этой проблемы заключалась в использовании прерываний, чтобы мочь остановить выполнение функции в нужный момент, передать контрол флоу какой-то effectfull функции(вместе со снапшотом состояния программы ProgramState a), которая может изменить это состояние и вернуть выполнение обратно в run. Так вот, в принципе это работает, но у меня не получается совместить это с еффектами, так как мне нужно значение из внешнего мира, а это означает, что мое прерывание должно иметь тип, который позволит достать это значениче(например IO a означаент, что прерывание должно быть в IO, чтобы я мог достать и использовать a).
Есть какие-то идеи как это решить?
Завернуть всё в Sem m из polysemy, потребовать самопальные эффекты Writes и Prints
тогда она будет не чистой
Это ещё почему, runWritesPure :: Sem (Writes : m) a -> Sem m (a, [String]) и потом в run :: Sem '[] a -> a и будет чистая функция
честно говоря не знаком с polysemy, но я предполагаю что работает это также как в free, где ты пишешь дсл, а потом можешь писать интерпретаторы в любой конечный стек
бтв по этому поводу можно поспорить
Обсуждают сегодня