кана
A64m
это просто ворнинг такой
кана
ворнинг о том, что для "" выбран дефолтный тип но он не должен выбирать дефолтный тип, так как тип четко известен
A64m
вывести естественно можно, он и выводит, но ворнинг всегда будет, где конкретный тип выводится
Aleksei (astynax)
Ворнинг не про то, что непонятно, что внутри врайтера. Тут очевидно, что строка. Ворнинг о том, что строковый литерал задефолтился в этом конкретном месте в строку
кана
да, я это понимаю, я же про это и пишу
кана
но зачем он задефолтился, если тип ЧЕТКО известен это же ровно то же самое, что и ("" :: String) - тут тип точно так же четко известен
Aleksei (astynax)
Потому что строковый литерал - полиморфный.
кана
f :: String -> ... f "" -- тоже будет ругаться?
Aleksei (astynax)
Точно так же компилятор предупреждает про дефолтинг численных литералов
кана
f :: String -> ... f "" -- тоже будет ругаться?
нет, в этом кейсе он не ругается, так как тип выводится как String из f в примере выше он точно так же выводится (из результата функции)
кана
Потому что строковый литерал - полиморфный.
но результат у нас строго String указан
Aleksei (astynax)
Считай, что у тебя там fromString "" и сравнение
Aleksei (astynax)
foo.hs:1:16: warning: [-Wtype-defaults] • Defaulting the following constraints to type ‘Integer’ (Eq a0) arising from a use of ‘elem’ at foo.hs:1:16-31 (Num a0) arising from the literal ‘1’ at foo.hs:1:16 • In the second argument of ‘($)’, namely ‘1 `elem` [1, 2, 3]’ In the expression: print $ 1 `elem` [1, 2, 3] In an equation for ‘main’: main = print $ 1 `elem` [1, 2, 3] | 1 | main = print $ 1 `elem` [1,2,3] | ^^^^^^^^^^^^^^^^
кана
потому что тут нигде не указан тип
кана
у меня тип указан
кана
Aleksei (astynax)
Да я тебя понял
Aleksei (astynax)
Но предполагаю, что смысл от ворнинга есть. Видимо, компилятор допускает разночтения...
A64m
тут это, небось, из-за instance (a ~ Char) => IsString [a] where
Зигохистоморфный
так как сделать такой парсер (parsec) чтобы понимал 1 1.0 -1 и прочее и ругался на 1.2. 1.2.3.4 в общем это пропускает P.parse (naturalOrFloat) "" "1.0.0"
кана
int = *много цифр* num = int » optional (string "." » int) что-нибудь типа
Зигохистоморфный
ну это понятно
кана
так а в чем проблема тогда?
Зигохистоморфный
мне надо так чтобы точка только раз могла быть или ниразу
Aleksei (astynax)
ну так опшнл это и даст
Зигохистоморфный
мне надо чтобы ругалось
кана
так он и будет ругаться
кана
вторая точка не подходит под парсер выше
кана
там же нет рекурсии
Зигохистоморфный
вот я и подумал о рекурсии
Aleksei (astynax)
> num = (,) <$> (many digit <|> pure "0") <*> ((char '.' >> many1 digit) <|> pure "0") > parse (num <* eof) "" "1" Right ("1","0") > parse (num <* eof) "" "1.0" Right ("1","0") > parse (num <* eof) "" "1.05" Right ("1","05") > parse (num <* eof) "" ".05" Right ("","05") > parse (num <* eof) "" ".05.0" Left (line 1, column 4): unexpected '.' expecting digit or end of input
кана
не очень понятно как этот код вообще работал
кана
writer же не принимает начальное состояние, он mempty использует
кана
он как-то стрелку-reader вывел наверное, WriterT же
Aleksei (astynax)
По результату то понятно, что ты String хочешь
кана
я к чему - execWriter вообще не принимает аргумента-начального состояния)
Aleksei (astynax)
И?
Aleksei (astynax)
Моноид же
кана
ну а я его передал
кана
и код работал
кана
и мое предположение - он там как-то вывел reader так как WriterT
кана
собственно да, он действительно вывел Reader из стрелки
кана
:t flip execWriterT flip execWriterT :: b -> WriterT c ((->) b) a -> c
кана
поэтому очевидно был ворнинг о том, что не ясно, что за тип у ""
кана
так как "" никакого отношения к Writer не имел, это энв случайно образованного ридера, который нигде не использовался (не было ask явного как минимум)
кана
вот тебе и статически типизированный хаскель с выводом типов
кана
топ история, нужно куда-то ее запостить
кана
короче Monad у (->) в прелюдии - такая себе идея уже второй раз за день натыкаюсь на него
кана
первый раз было это
кана
Aleksei (astynax)
Инстанс есть, чтобы его застолбить и не допускать сирот в либах
A64m
впервые в истории человечества от деолтинг-ворнинга была какая-то польза (но это не точно)
Cheese
Инстанс есть, чтобы его застолбить и не допускать сирот в либах
ух ты, первый раз слышу разумное обоснование. раньше говорили "потому что ничему не противоречит"
Alexander
всегда говорили - если есть инстанс его надо написать
Alexander
именно для этого
Alexander
а если ничему не противоречит => можно написать
A64m
потрясающая память!
https://www.flamewarriorsguide.com/warriorshtm/archivist.htm
Dmitrii
внезапно universum не экспортит writer @chshersh, почему так, редко используется?
Writer ликает память. Надо использовать Writer либо из пакета writer-cps либо строгий StateT
Alexander
Writer это монада для создания memory leaks
Alexander
сто раз же говорили уже
кана
так а почему в mtl не влючают Strict Writer на основе Strict стейта/cps-райтера?
кана
Расскажу я вам сейчас одну офигенную историю, что со мной произошла. Итак, коллега решал для себя простенькую задачу по реализации интерпретатора бреинфак-подобного языка на js и я решил, что чего бы мне тоже не написать, на хаскеле естественно. Сразу была написана фримонада для AST и интерпретатор. Команды всего четыре, инкремент значения в памяти, декремент, установка в нуль и вывод. Поэтому для интерпретатора я заюзал StateT для памяти и WriterT для вывода. Думаю, код понятен, если работали с free (если нет, пишите, я все с радостью объясню в любое время суток). runBrainscrambler :: Brainscrambler a -> String runBrainscrambler = flip execWriterT "" . flip evalStateT 0 . foldFree go where go (Increment next) = modify succ >> pure next go (Decrement next) = modify pred >> pure next go (PushZero next) = put 0 >> pure next go (Output next) = get >>= tell . show >> pure next ВАЖНО ЗАМЕТИТЬ: код полностью рабочий, он не просто компилируется, он выдаст правильный результата на любых примерах. Но тут есть несколько ошибок, которые я не заметил, так как не написал тайпинги, мол хаскель сам выведет. Кто их уже заметил, молодец, остальным тоже советую посидеть и поискать. В проекте было подключено OverloadedString-расширение, так что любой строковой литерал полиморфен и компилятор будет кидать ворнинг о том, что "используется дефолтный тип, так как тип не указан явно", если тип не указать явно. Собственно в коде выше "" не аннотирован явно, но тип четко выводится из результата функции (String). Ворнинг тем не менее был: • Defaulting the following constraint to type ‘[Char]’ IsString b0 arising from the literal ‘""’ • In the second argument of ‘flip’, namely ‘""’ In the first argument of ‘(.)’, namely ‘flip execWriterT ""’ In the expression: flip execWriterT "" . flip evalStateT (0 :: Int) . foldFree go | 16 | = flip execWriterT "" | ^^ Для меня это стала загадкой, с просьбой решить ее я обратился в @haskellru, но там никто не смог помочь (говорили про то, что ворнинг из-за того, что нет аннотации, но не увидили, что тип четко известен, полагаю никто, как я, в чужой код не вчитывается). И вот я решил добавить тайпинги и весь код сломался: go :: BrainscramblerF a -> StateT Int (Writer String) a И вот тут-то я наконец понял, в чем дело. 1. У меня Writer, а не WriterT, поэтому нужно execWriter, а не execWriterT 2. (exec|eval|run)WriterT? не принимают начального "состояния", так как они работают с моноидом и берут в качестве начального вывода mempty. Эти две ошибки вместе дают ОЧЕНЬ интересный результат. Раз execWriterT не принимает начального состояния, то почему выше код работал? Что именно flip флипал? И тут до меня дошло озарение я в спешке побежал проверять: :t flip execWriterT flip execWriterT :: b -> WriterT c ((->) b) a -> c Именно, из-за flip хаскель вывел инстанс монады для (->) b, то есть Reader. И использовал этот (->) b как монаду для дыры монадного трансформера WriterT. Тот "" был не начальным состоянием WriterT, а энвароментом Reader, который в коде нигде явно не используется (нет ask), поэтому и тип вывести не получается, поэтому и был ворнинг. Это эпичнейшая ошибка в моей жизни, скажу честно. Итоговый правильный код выглядит так: runBrainscrambler :: Brainscrambler a -> String runBrainscrambler = execWriter . flip evalStateT (0 :: Int) . foldFree go where go :: BrainscramblerF a -> StateT Int (Writer String) a go (Increment next) = modify succ >> pure next go (Decrement next) = modify pred >> pure next go (PushZero next) = put 0 >> pure next go (Output next) = get >>= tell . show >> pure next Вот вам и статически типизированный хаскель с выводом типов - выведет даже неверный код в верный, как тут хаскель не любить-то.
Anatolii
вот это конечно брэинфак настоящий
Leonid 🦇
Расскажу я вам сейчас одну офигенную историю, что со мной произошла. Итак, коллега решал для себя простенькую задачу по реализации интерпретатора бреинфак-подобного языка на js и я решил, что чего бы мне тоже не написать, на хаскеле естественно. Сразу была написана фримонада для AST и интерпретатор. Команды всего четыре, инкремент значения в памяти, декремент, установка в нуль и вывод. Поэтому для интерпретатора я заюзал StateT для памяти и WriterT для вывода. Думаю, код понятен, если работали с free (если нет, пишите, я все с радостью объясню в любое время суток). runBrainscrambler :: Brainscrambler a -> String runBrainscrambler = flip execWriterT "" . flip evalStateT 0 . foldFree go where go (Increment next) = modify succ >> pure next go (Decrement next) = modify pred >> pure next go (PushZero next) = put 0 >> pure next go (Output next) = get >>= tell . show >> pure next ВАЖНО ЗАМЕТИТЬ: код полностью рабочий, он не просто компилируется, он выдаст правильный результата на любых примерах. Но тут есть несколько ошибок, которые я не заметил, так как не написал тайпинги, мол хаскель сам выведет. Кто их уже заметил, молодец, остальным тоже советую посидеть и поискать. В проекте было подключено OverloadedString-расширение, так что любой строковой литерал полиморфен и компилятор будет кидать ворнинг о том, что "используется дефолтный тип, так как тип не указан явно", если тип не указать явно. Собственно в коде выше "" не аннотирован явно, но тип четко выводится из результата функции (String). Ворнинг тем не менее был: • Defaulting the following constraint to type ‘[Char]’ IsString b0 arising from the literal ‘""’ • In the second argument of ‘flip’, namely ‘""’ In the first argument of ‘(.)’, namely ‘flip execWriterT ""’ In the expression: flip execWriterT "" . flip evalStateT (0 :: Int) . foldFree go | 16 | = flip execWriterT "" | ^^ Для меня это стала загадкой, с просьбой решить ее я обратился в @haskellru, но там никто не смог помочь (говорили про то, что ворнинг из-за того, что нет аннотации, но не увидили, что тип четко известен, полагаю никто, как я, в чужой код не вчитывается). И вот я решил добавить тайпинги и весь код сломался: go :: BrainscramblerF a -> StateT Int (Writer String) a И вот тут-то я наконец понял, в чем дело. 1. У меня Writer, а не WriterT, поэтому нужно execWriter, а не execWriterT 2. (exec|eval|run)WriterT? не принимают начального "состояния", так как они работают с моноидом и берут в качестве начального вывода mempty. Эти две ошибки вместе дают ОЧЕНЬ интересный результат. Раз execWriterT не принимает начального состояния, то почему выше код работал? Что именно flip флипал? И тут до меня дошло озарение я в спешке побежал проверять: :t flip execWriterT flip execWriterT :: b -> WriterT c ((->) b) a -> c Именно, из-за flip хаскель вывел инстанс монады для (->) b, то есть Reader. И использовал этот (->) b как монаду для дыры монадного трансформера WriterT. Тот "" был не начальным состоянием WriterT, а энвароментом Reader, который в коде нигде явно не используется (нет ask), поэтому и тип вывести не получается, поэтому и был ворнинг. Это эпичнейшая ошибка в моей жизни, скажу честно. Итоговый правильный код выглядит так: runBrainscrambler :: Brainscrambler a -> String runBrainscrambler = execWriter . flip evalStateT (0 :: Int) . foldFree go where go :: BrainscramblerF a -> StateT Int (Writer String) a go (Increment next) = modify succ >> pure next go (Decrement next) = modify pred >> pure next go (PushZero next) = put 0 >> pure next go (Output next) = get >>= tell . show >> pure next Вот вам и статически типизированный хаскель с выводом типов - выведет даже неверный код в верный, как тут хаскель не любить-то.
Пиши на ruHaskell мини-статью
Dmitrii
так а почему в mtl не влючают Strict Writer на основе Strict стейта/cps-райтера?
Потому что Кмет нашёл способ, когда ленивое поведение Writer на самом деле полезно, и он использовал это. Поэтому Writer имеет право на жизнь, хоть и очень маленькое. Но это одна из проблем Haskell — про желаемые решения надо узнавать через сарафанное радио, а по дефолту не то, что нужно большинству. И всякие туториалы типа LYAH устарели и рассказывают про Writer с теоретической точки зрения, игнорируя практику
Дима
Writer.SegmentationFault
Антон
Writer.SegmentationFault
Зачем так? Надо Writer.Error, Writer.Exception или даже Wtiter.Panic
Dmitry
мм, а есть что-то для генерирования отчётов / pretty printing ? ну, как wl-pretty, только более общее - т.е задаешь layout - заголовки(группы), колонки - и оно тебе красиво печатает в зависимости от бэкенда?
Dmitrii
я не к тому, чтобы заменить, а что бы сделать как со стейтом: Writer.Lazy, Writer.Strict / Writer.Leak, Writer.NonLeak)
Ну, там сложней, потому что на самом деле есть три (если не больше) способов сделать Writer. Writer.Lazy и Writer.Strict уже есть, но они оба ликают https://hackage.haskell.org/package/transformers
Anonymous
сто раз же говорили уже
https://mobile.twitter.com/gabrielg439/status/659170544038707201?lang=en
Alexander
до этого тоже говориои