LINUX.ORG.RU

Однострочник из ghci:

Prelude Control.Monad Control.Monad.State.Strict> runStateT (forever $ get >>= lift . print >> modify (+1)) 0

Коротко говоря, используй монаду State.

unC0Rr ★★★★★
()
Последнее исправление: unC0Rr (всего исправлений: 1)

Можно просто протаскивать старое значение ручками:

myLoop :: Int -> IO ()                                                          
myLoop oldVal = do                                                              
  line <- getLine                                                               
  let newVal = read line :: Int                                                 
  print $ newVal - oldVal                                                       
  myLoop newVal                                                                 
                                                                                
main :: IO ()                                                                   
main = myLoop 0

Можно абстрагировать работу с состоянием через StateT:

myLoop :: StateT Int IO ()                                                      
myLoop = forever $ do                                                                     
  line <- liftIO getLine                                                        
  let newVal = read line :: Int                                                 
  oldVal <- get                                                                 
  liftIO $ print $ newVal - oldVal                                              
  put newVal                                                                                                                                            
                                                                                
main :: IO ()                                                                   
main = evalStateT myLoop 0                                                            

Softwayer ★★
()
Последнее исправление: Softwayer (всего исправлений: 1)

Странный вопрос от эксперта. Протаскивай состояние через вложенную функцию. Компилятор ее эффективно скомпилирует.

dave ★★★★★
()

Тогда сработает оптимизация хвостового вызова, и получится что-то типа бесконечного while. IORef плох тем, что создается нагрузку на GC, хотя здесь это можно не брать в расчет.

dave ★★★★★
()
Ответ на: комментарий от dave

Странный вопрос от эксперта.

Во-во. Вопрос проженного императивщика. Щас бы использовать понятие «цикл» из императивщины в функциональщине, тем более с претензией на чистоту. И вопрос не соответствует содержанию: надо изменить внешнее значение, а не получить.

anonymous
()

Тут явно нужен хистоморфизм.

anonymous
()
Ответ на: комментарий от anonymous

Щас бы использовать понятие «цикл» из императивщины в функциональщине

Чем forM и replicateM не функциональные или не циклы? Изначально наткнулся именно в forM на потребность значение между итерациями сохранить.

надо изменить внешнее значение, а не получить

Зачем изменить? Получить с предыдущей итерации значение. «Изменить» — это уже костыль реализации.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

А если просто считать сразу все значения в список, а уже после этот список обработать?

main = do                                                                       
    xs <- many readLn :: IO [Int]                                               
    print $ zipWith (-) xs (0:xs)
Crocodoom ★★★★★
()
Ответ на: комментарий от Crocodoom

Там типа диалоговая система. Чтобы следующее число получить надо сначала вычисление вернуть.

Если прочитать, то да, хоть zip, хоть fold.

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Чем forM и replicateM ... не циклы?

Я поверхностно знаком с хаскелем. Тем, что это функции (рекурсивные). А то, что рекурсией «чисто случайно» можно реализовать императивный цикл, это - «просто повезло». Зря ты полез с императивными заблуждениями в монады (в forM буква M - думаю означает монаду). Лучше поиграйся с простой функциональщиной без монад, в рекурсии, и лучше на ML-языках(sml, ocaml и тп). А то сразу полез в монады для реализации циклов, из пушки по воробьям.

Зачем изменить? Получить с предыдущей итерации значение.

Я не спец в хаскеле. Просто получить значение из внешней видимости можно простым использованием (имени) значения.

anonymous
()
Ответ на: комментарий от anonymous

А то, что рекурсией «чисто случайно» можно реализовать императивный цикл, это - «просто повезло».

Есть раздел математики, который посвящен этой теме.

dave ★★★★★
()
Ответ на: комментарий от dave

«чисто случайно»
«просто повезло».

Есть раздел математики, который посвящен этой теме.

Кавычек не хватило, чтобы понять, что это сарказм?

anonymous
()
Ответ на: комментарий от anonymous

Я поверхностно знаком с хаскелем.

А то сразу полез в монады для реализации циклов, из пушки по воробьям.

Если задача сама по себе вида «прочитать n строк с числами и сделать ...», то без цикла никак. Или рекурсии.

Просто получить значение из внешней видимости можно простым использованием (имени) значения.

Из forM/replicateM во внешнюю видимость ничего нельзя положить пока цикл не закончится. Для foldr/foldl проблема решается легко: можно результат представить в виде кортежа и добавить служебные данные, а вот для forM никак, только в явную рекурсию разворачивать (State некрасиво, потом весь код в liftIO)

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Или рекурсии.

Вот и пиши рекурсии. И поймешь, что это ничуть несложнее написания циклов.

получить
положить

Кто-то путается в показаниях, или не понимает разницы между ними.

anonymous
()
Ответ на: комментарий от anonymous

Вот и пиши рекурсии. И поймешь, что это ничуть несложнее написания циклов.

Библиотечные forM и replicateM рекурсию не позволяют. Переписывать библиотечные функции «просто потому что могу» смысла не вижу.

Кто-то путается в показаниях, или не понимает разницы между ними.

Мне не надо класть во внешнюю видимость. Мне надо получить из предыдущей итерации цикла.

То есть было бы что-то вроде

forM' data $ \(i, prev_val) ->
  val <- getLine
  process val prev_val
  return val

вопросов бы не было. Но библиотечной функции с такой функциональностью я не нашёл. Написать, что ли...

monk ★★★★★
() автор топика
Ответ на: комментарий от monk

Из forM/replicateM во внешнюю видимость ничего нельзя положить пока цикл не закончится. Для foldr/foldl проблема решается легко: можно результат представить в виде кортежа и добавить служебные данные, а вот для forM никак, только в явную рекурсию разворачивать (State некрасиво, потом весь код в liftIO)

Ещё есть foldM. Ты бы привёл более-менее приближенный к реальности пример.

Crocodoom ★★★★★
()
Ответ на: комментарий от monk

Библиотечные forM и replicateM рекурсию не позволяют. Переписывать библиотечные функции «просто потому что могу» смысла не вижу.

А зачем ты используешь forM и replicateM? «Просто потому что могу»? То есть сперва создал проблему, потом героически его решаешь? Нет бы сразу написать рекурсивно, например, как первый пример Софтвейера. Я даже уверен, было бы короче и использовал бы меньше абстракций (с монадами). Но императивное прошлое взяло вверх и ты геройствуешь в функциональщине посредством монад.

anonymous
()
Ответ на: комментарий от Crocodoom

Ещё есть foldM

Вот её я и искал. Благодарю!

monk ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.