Size: a a a

2021 April 03

к

кана in Haskell
data Free f a
 = Pure a
 | Free (f (Free f a))
 deriving (Functor)

instance Functor f => Applicative (Free f) where
 pure = Pure
 (<*>) = ap

instance Functor f => Monad (Free f) where
 Pure x >>= f = f x
 Free m >>= f = Free (fmap (>>= f) m)

data MyIOT a
 = Print Text a
 | GetLine (Text -> a)
 deriving (Functor)

myPrint :: Text -> Free MyIOT ()
myPrint str = Free (Print str (Pure ()))

myGetLine :: Free MyIOT Text
myGetLine = Free (GetLine Pure)

foldPrints :: Free MyIOT a -> Free MyIOT a
foldPrints (Free (Print a (Free (Print b next)))) = foldPrints $ Free (Print (a <> "\n" <> b) next)
foldPrints (Free (Print a next)) = Free (Print a (foldPrints next))
foldPrints (Free (GetLine next)) = Free (GetLine (foldPrints . next))
foldPrints (Pure x) = Pure x

alg :: MyIOT a -> IO a
alg (Print a next) = putStrLn ("output: " <> a) >> pure next
alg (GetLine next) = next <$> (putStr "input: " >> getLine)

runFree :: Monad m => (forall x. f x -> m x) -> Free f a -> m a
runFree f (Pure x) = pure x
runFree f (Free m) = f m >>= runFree f

main2 :: IO ()
main2 = runFree alg $ foldPrints do
 myPrint "Hello"
 myPrint "enter your name:"
 name <- myGetLine
 myPrint "your name is"
 myPrint name


с оптимизацией
*Main> main2
output: Hello
enter your name:
input: kana
output: your name is
kana


без оптимизации
*Main> main2
output: Hello
output: enter your name:
input: kana
output: your name is
output: kana
источник

MK

Maxim Koltsov in Haskell
С другой стороны, можно делать NbE в котором настоящий хаскель будет вычислять ту часть кода, которая не зависит от того что в биндах
источник

MK

Maxim Koltsov in Haskell
Но хз насколько это полезно
источник

t

toriningen in Haskell
кана
data Free f a
 = Pure a
 | Free (f (Free f a))
 deriving (Functor)

instance Functor f => Applicative (Free f) where
 pure = Pure
 (<*>) = ap

instance Functor f => Monad (Free f) where
 Pure x >>= f = f x
 Free m >>= f = Free (fmap (>>= f) m)

data MyIOT a
 = Print Text a
 | GetLine (Text -> a)
 deriving (Functor)

myPrint :: Text -> Free MyIOT ()
myPrint str = Free (Print str (Pure ()))

myGetLine :: Free MyIOT Text
myGetLine = Free (GetLine Pure)

foldPrints :: Free MyIOT a -> Free MyIOT a
foldPrints (Free (Print a (Free (Print b next)))) = foldPrints $ Free (Print (a <> "\n" <> b) next)
foldPrints (Free (Print a next)) = Free (Print a (foldPrints next))
foldPrints (Free (GetLine next)) = Free (GetLine (foldPrints . next))
foldPrints (Pure x) = Pure x

alg :: MyIOT a -> IO a
alg (Print a next) = putStrLn ("output: " <> a) >> pure next
alg (GetLine next) = next <$> (putStr "input: " >> getLine)

runFree :: Monad m => (forall x. f x -> m x) -> Free f a -> m a
runFree f (Pure x) = pure x
runFree f (Free m) = f m >>= runFree f

main2 :: IO ()
main2 = runFree alg $ foldPrints do
 myPrint "Hello"
 myPrint "enter your name:"
 name <- myGetLine
 myPrint "your name is"
 myPrint name


с оптимизацией
*Main> main2
output: Hello
enter your name:
input: kana
output: your name is
kana


без оптимизации
*Main> main2
output: Hello
output: enter your name:
input: kana
output: your name is
output: kana
но такое уже не сработает, например, если у нас есть что-то типа State с Get | Set, которые мы хотим "наоптимизировать" в GetMultiple | Set
источник

t

toriningen in Haskell
или сработает?
источник

к

кана in Haskell
ну, я могу придумать хак, который сработает
источник

KV

Kirill Valyavin in Haskell
toriningen
или сработает?
Чтобы проанализировать кусок кода, содержащий бинд, надо как бы матчить по континуейшену, т. е. надо перечислить все возможные варианты последующих инструкций в зависимости от "прочитанного" значения, и применить оптимизацию только в уместных случаях

Вот монады, которые позволяют так делать, это и есть селективы
источник

к

кана in Haskell
кана
ну, я могу придумать хак, который сработает
нет, не могу, не сработает
источник

K

Kir in Haskell
кана
ну да, достаточно красиво
В форвард джампы может?
источник

к

кана in Haskell
ну да, именно в форвард джампах же и заключалось условие задачи
источник

к

кана in Haskell
источник

к

кана in Haskell
из-за возможности форвард джампов я просто делаю все в два этапа, в пером высчитываю оффсеты для лейблов и конверчу, во втором заменяю лейблы на уже высчитанные оффсеты
источник

K

Kir in Haskell
toriningen
У меня небольшой теоретический и, скорее всего, глупый вопрос. Если вдруг что, смело гоните меня, насмехайтесь надо мной, и я пойду обратно в haskell start.

Так вот... Есть у меня экземпляр фримонады, пусть будет поверх какой-то простой структуры с конструкторами-операциями. Я хочу написать эдакий "оптимизатор" для экземпляра такой монады, который мог бы, пользуясь знаниями о семантике вот этих вот операций, поверх которых она построена, выполнять изменения, затрагивающие много узлов низлежащей структуры — например, сворачивать несколько операций в одну, или менять их относительный порядок, или анализировать взаимозависимости для того, чтобы отмаркировать какие-то узлы, как пригодные для параллелизации и т.д. и т.п.

Сложность в том, что я не до конца понимаю, как это должно выглядеть. Если бы это была чистая структура данных аля дерево, то тут все просто — я описываю предикаты для групп узлов, матчу узлы по этим предикатам, скармливаю выбранные узлы в функцию, которая порождает новые узлы, и заменяю поддеревье и итеративно продолжаю этот процесс до полного просветления, пока не перестанет что-то матчиться.

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

Окей, пусть я отказываюсь от идеи видеть "все дерево" целиком, и пишу некий "оптимизирующий интерпретатор", который на самом деле выполняет аргументы биндов, чтобы получить дальнейшие ветки, но я сталкиваюсь с тем, что аргументы биндов мало того, что нетотальны, я еще и не знаю наперед, если у них какие-то "особые точки". Т.е. для того, чтобы выполнить следующий коллбэк бинда, мне нужно передать ему фактическое "значение внутри контекста", а у меня-то его и нет. Что ж мне, табулировать все возможные значения? Звучит глупо и невозможно.

Я пытаюсь изобрести какую-то странную чухню, или у этой задачи есть решение?
Что-то сделать можно с аппликативами (но у них выразительной силы мало), фримонаду можно только стоить в Codensity, а потом развернуть.
источник

K

Kir in Haskell
кана
из-за возможности форвард джампов я просто делаю все в два этапа, в пером высчитываю оффсеты для лейблов и конверчу, во втором заменяю лейблы на уже высчитанные оффсеты
Стандартный двухпроходовый ассемблер, в общем
источник

к

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

к

кана in Haskell
Переслано от кана
с тардисом вышло так
источник

K

Kir in Haskell
Если ты добавляешь в программу сингулярности, то будь готов встретить лицом горизонт событий
источник

t

toriningen in Haskell
Kir
Что-то сделать можно с аппликативами (но у них выразительной силы мало), фримонаду можно только стоить в Codensity, а потом развернуть.
*страшно говорит по-теоркатски* можно ли где-то почитать об этом простыми словами?
источник

к

кана in Haskell
источник

к

кана in Haskell
там и ссылка на пейпер, и хаддоки
источник