Каковы функциональные эквиваленты обязательных операторов завершения и других проверок петли?

Скажем, я имею ниже логики. Как написать это в Функциональном программировании?

    public int doSomeCalc(int[] array)
    {
        int answer = 0;
        if(array!=null)
        {
            for(int e: array)
            {
                answer += e;
                if(answer == 10) break;
                if(answer == 150) answer += 100;
            }
        }
        return answer;
    }

Примеры в большинстве блогов, статьях... Я вижу, просто объясняет, что простой случай одной прямой математической функции говорит 'Сумму'. Но, я имею логику, подобную вышеупомянутому, написанному на Яве, и хотел бы мигрировать это к функциональному коду в Clojure. Если мы не можем сделать вышеупомянутого в FP, то вид продвижений для FP не указывает это явно.

Я знаю, что вышеупомянутый код полностью обязателен. Это не было написано с предусмотрительностью перемещения его к FP в будущем.

35
@WillNess: Я просто хотел упомянуть его, потому что это может использоваться, чтобы оставить сложное вычисление в любом пункте. Это - вероятно, не лучшее решение для OP' s конкретный пример.
добавлено автор Giorgio, источник
Обратите внимание, что комбинация , разрыв и дает ответ , может быть заменена возвращение в петле. В FP вы могли осуществить это раннее возвращение, используя продолжения, видеть, например. en.wikipedia.org/wiki/Continuation
добавлено автор Giorgio, источник
В этом случае: takeWhile .
добавлено автор John Washburn, источник
@Giorgio you' право ре, это - самое всестороннее в целом. на самом деле этот вопрос очень широк, IYKWIM (т.е. был бы замкнут ТАК в сердцебиении).
добавлено автор Rex Space, источник
Продолжения @Giorgio были бы огромным излишеством здесь. It' s петля так или иначе, чтобы назвать ее следующее повторение вы делаете последний вызов, так чтобы сломать вас просто don' t называют его больше и просто дают ответ. Для вложенные петли или другой сложный поток управления, that' s, где вы могли бы использовать продолжения вместо того, чтобы подняться, чтобы реструктурировать ваш код, чтобы использовать вышеупомянутую простую технику (который должен всегда быть возможным, но может привести к структуре чрезмерно сложного кода, которая была бы более или менее объясняют продолжение; и больше чем для одной точки выхода you' d, конечно, нужны они).
добавлено автор Rex Space, источник

6 ответы

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

doSomeCalc :: [Int] -> Int
doSomeCalc values = foldr1 combine values
  where combine v1 v2 | v1 == 10  = v1
                      | v1 == 150 = v1 + 100 + v2
                      | otherwise = v1 + v2

Разрушение этого линию за линией в случае, если вы не знакомы с синтаксисом Хаскелла, это работает как это:

doSomeCalc :: [Int] -> Int

Определяет тип функции, принимая список ints и возвращая единственный интервал.

doSomeCalc values = foldr1 combine values

Основная часть функции: учитывая аргумент ценности , возвратите foldr1 названный с аргументами объединение (который мы определим ниже), и ценности . foldr1 является вариантом сгиба, примитивного, который начинается с набора сумматора к первой ценности списка (следовательно 1 на имя функции), затем объединяет его, используя пользователя определенная функция слева направо (который обычно называют правильным сгибом , следовательно r на имя функции). Так foldr1 f [1,2,3] эквивалентно f 1 (f 2 3) (или f (1, f (2,3)) в более обычном подобном C синтаксисе).

  where combine v1 v2 | v1 == 10  = v1

Определение объединение местная функция: это получает два аргумента, v1 и v2 . Когда v1 равняется 10, это просто возвращает v1 . В этом случае v2 никогда не оценивается , таким образом, петля останавливается здесь.

                      | v1 == 150 = v1 + 100 + v2

Альтернативно, когда v1 равняется 150, добавляют дополнительные 100 к нему и добавляют v2.

                      | otherwise = v1 + v2

И, если ни одно из тех условий не верно, просто добавляет v1 к v2.

Теперь, это решение несколько характерно для Хаскелла, потому что то, что правильный сгиб заканчивается, если объединяющаяся функция не оценивает свой второй аргумент, вызывается стратегией отложенных вычислений Хаскелла. Я не знаю Clojure, но я полагаю, что он использует строгую оценку, таким образом, я ожидал бы, что он будет иметь , сгиб функционирует в его стандартной библиотеке, которая включает определенную поддержку раннего завершения. Это часто называют foldWhile , foldUntil или подобный.

Беглый взгляд на документацию библиотеки Clojure предполагает, что это немного отличается от большинства функциональных языков в обозначении, и что , сгиб не то, что вы ищете (это - более современный механизм, нацеленный на предоставление возможности параллельного вычисления), но уменьшить более прямой эквивалент. Раннее завершение происходит, если уменьшил , функция вызвана в вашей функции объединения. Я не на 100% уверен, что понимаю синтаксис, но я подозреваю то, что вы ищете, что-то вроде этого:

(reduce 
    (fn [v1 v2]
        (if (= v1 10) 
             (reduced v1)
             (+ v1 v2 (if (= v1 150) 100 0))))
    array)

NB: оба перевода, Хаскелл и Клоджьюр, не совсем правильные для этого определенного кода; но они передают общую суть его - посмотрите обсуждение в комментариях ниже для определенных проблем с этими примерами.

45
добавлено
@WillNess Это - upvoted, потому что это - наиболее понятный перевод и объяснение. То, что это неправильно, является позором, но относительно неважный здесь, потому что небольшие ошибки не отрицают то, что ответ в других отношениях полезен. Но конечно это должно быть исправлено.
добавлено автор Mark Ransom, источник
@WillNess: Я не знаю о Хаскелле, но нашел это просвещение ответа. Если у этого есть ошибка, пожалуйста, используйте отредактировать кнопку, чтобы сделать его лучше.
добавлено автор olive_tree, источник
@WillNess - идите вперед и отредактируйте его. Ваши комментарии хороши, но я don' у t есть время, чтобы зафиксировать ошибку в данный момент.
добавлено автор Jules, источник
так да, "самый неправильный ответ" wasn' t совершенно верно.
добавлено автор Rex Space, источник
@AndrewT. да, поскольку я сказал ре: механизмы обнаружения знаний. это - конечно, обсуждение, не подходящее здесь; возможно, на meta, если вообще (т.е. это затрагивает очень основное из того, что SE). Это, тем не менее, на HNQ? Это doesn' t показывают для меня.---кроме того, объяснение в порядке в целом; просто то, что код не правильный перевод OP' s определенный код. Я didn' t downvote BTW.
добавлено автор Rex Space, источник
@Jules хорошо, который я только сказал половине правды там (но это подразумевалось) - it' s слишком большой из изменения; слишком много работы. Это было бы похоже на меня пишущий совершенно новый ответ. тогда, почему я не отправил бы его под своим собственным именем?:) небольшая ошибка в коде Clojure уже исправляется в ответе вниз ниже, также.---хорошо, I' ve отредактирован в маленьком примечании в основании.---вы прочитали ту связь о Джоне Маккарти? it' s прочитанное хорошее.
добавлено автор Rex Space, источник
как, например, foldl' Ломка преобразователя данных разрыва уменьшила список acc = foldr, недостатки (\acc-> acc) перечисляют acc, где недостатки x r acc =, если (ломают acc x), тогда (еще уменьшил acc x) (r $! преобразователь данных acc x) , с соответствующим разрывом проверяют функцию разрыв . $! делает для строгой оценки, более эффективной здесь. (но that' s Haskell-конкретный). Clojure' s уменьшают </ код> действительно слева направо, и там v1 - тот, относящийся к накапливаемой стоимости; все еще there' s ошибка в вашем переводе Clojure также. - первый комментарий упомянул перевод Хаскелла с foldr1 .
добавлено автор Rex Space, источник
@MooingDuck я должен был бы переписать его целый. Это может быть сделано, но я чувствую it' d быть слишком самонадеянным меня, чтобы сделать это. There' s это известное высказывание Исааком Ньютоном я думаю, что это было, как он заявил, что некоторая проблема и люди чувствовали, что он объяснил решение их из-за общего настроения понимания, что он, "объяснил он" им. Но он на самом деле просто заявил проблему. Я don' t помнят специфические особенности.
добавлено автор Rex Space, источник
это забавный, как самый неправильный ответ получает большую часть upvotes на SE.... it' s хорошо, чтобы сделать ошибки, you' ре в хорошая компания:), также. Но механизм обнаружения знаний на SO/SE определенно сломан.
добавлено автор Rex Space, источник
имена v1 v2 запутывающие: v1 является "стоимостью от множества", но v2 является накопленным результатом. и ваш перевод ошибочен, я верю, OP' s петля выходит, когда , накопленный (от левого) стоимость, совершает нападки 10, не некоторый элемент во множестве. То же самое с увеличиванием 100. Если использовать сгибы здесь, используйте левый сгиб с ранним выходом, некоторым изменением на foldlWhile здесь.
добавлено автор Rex Space, источник
, Ломающий это линию за линией в случае, если you' ре, не знакомое с Haskell' s синтаксис - Вы - мой герой. Хаскелл - тайна мне.
добавлено автор markhorrocks, источник
Немного лакомого кусочка , когда остановка рано в сгиб на самом деле работает без дополнительной работы. Ваш сгиб должен быть ленивым, ваша рабочая функция должна быть ленивой. Или, лучше сказал, вам нужна рабочая функция, которая является умножением на некотором monoid, это сочло бы абсорбирующий элемент этого monoid где-нибудь в списке, и выполнение так не приведет ни к какому дальнейшему требованию к следующим элементам списка. Я на самом деле написал работу об этом: mathematik.uni-marburg.de / ~ lobachev/papers/lobachev-flops12.‌ ​ PDF
добавлено автор ineedtosleep, источник
@WillNess don' t забывают, что этот вопрос в настоящее время находится на HNQ, где многие пользователи могут только upvote (от премии ассоциации), но не downvote. Кроме того, как кто-то, кто doesn' t пишут Хаскеллу или Клоджьюру, подробное объяснение в этом ответе убедило бы достаточно для меня к upvote это, правильная ли информация или неправильная (я didn' t признают любые посты на этом конкретном Вопросами и ответами хотя).
добавлено автор Suraj, источник
Код Clojure почти правилен, но условие (= v1 150) использует стоимость перед v2 (иначе. e ), суммирован к нему.
добавлено автор fileyfood500, источник

Вы могли легко преобразовать его в рекурсию. И у этого есть хороший оптимизированный хвостом рекурсивный вызов.

Псевдокод:

public int doSomeCalc(int[] array)
{
    return doSomeCalcInner(array, 0);
}

public int doSomeCalcInner(int[] array, int answer)
{
    if (array is empty) return answer;

   //not sure how to efficiently implement head/tails array split in clojure
    var head = array[0]//first element of array
    var tail = array[1..]//remainder of array

    answer += head;
    if (answer == 10) return answer;
    if (answer == 150) answer += 100;

    return doSomeCalcInner(tail, answer);
}
31
добавлено
@leftaroundabout, Который поднимает некоторые вопросы, такие как: Почему вы думаете GOTO </ код> плох? (Чтобы быть ясным, I' m не предъявляющий любую претензию здесь, на ли it' s хороший или плохой. Я просто хочу знать ваше рассуждение.), Почему вы выбираете хвостовую рекурсию и не включаете рекурсию в целом, последние вызовы в целом или вызовы функции в целом (или вы включаете некоторых или всех тех, если так, почему?)?
добавлено автор steve, источник
Да. Функциональный эквивалент петле - хвостовая рекурсия, и функциональный эквивалент условному предложению - все еще условное предложение.
добавлено автор Lawrence B. Crowell, источник
@Jö rgWMittag I' d скорее говорят, что хвостовая рекурсия - функциональный эквивалент, чтобы GOTO . (Не совсем как плохо, но все еще довольно неловкий.) Эквивалент петле, как Жюль говорит, является подходящим сгибом.
добавлено автор zarose, источник
@8bittree I didn' t действительно намереваются выбрать хвостовую рекурсию. Как обсужденный J_mie6, общая рекурсия мог бы быть тем, что нужно считать аналогичным GOTO. Однако и that' s, где I' m прибывающий отсюда, хорошо написанный нехвост - рекурсивный код имеет тенденцию не быть такой” патологически рекурсивный”. Наоборот, функциональным программистам нравится излагать их код таким способом, которым уравнения определения почти обстоятельно объясняют инварианты. Но это не проведено в жизнь механизмом рекурсии по сути (в отличие от этого, с петлями, которые действительно ограничивают сумму ерунды, которую программист может передать).
добавлено автор zarose, источник
@J_mie6, которым причина, я рассматриваю хвостовую рекурсию больше как GOTO , состоит в том, что необходимо сделать трудную бухгалтерию того, какие аргументы в том, что государство пройдено к рекурсивному вызову, чтобы гарантировать ему на самом деле, ведут себя, как предназначено. Это не необходимо для той же самой степени в области прилично написанных обязательных петель (где it' s довольно ясный, что переменные с фиксацией состояния и как они изменяются в каждом повторении), ни в naï рекурсия ve (то, где обычно не много сделано с аргументами, и вместо этого результатом, собрано довольно интуитивным способом)...
добавлено автор zarose, источник
... Что касается сгибов: you' право ре, традиционный сгиб (catamorphism) является очень определенным видом петли, но эти схемы рекурсии могут быть обобщены (сборник изречений - / apo-/hylomorphisms); коллективно это IMO надлежащая замена для обязательных петель.
добавлено автор zarose, источник
У @J_mie6 рекурсивный эквивалент ваш "традиционный для петли" также есть начало, конец, и детерминированный шаг и it' s легкий показать посредством индукции этому it' остановка ll.
добавлено автор Doval, источник
продолжение следует: этим я подразумеваю, что у сгиба есть детерминированное количество повторений. Для любого данного списка вы знаете точно, сколько повторений, которые берет "петля". Таким образом, сгиб похож на традиционное для петли (в том смысле, что у этого есть начало, конец и детерминированный шаг), и рекурсивная функция хвоста похожа некоторое время на петлю, где это неразрешимо теперь долго, это берет, чтобы вычислить. С точки зрения грубой силы тогда, неограниченная рекурсия - реальное GOTO
добавлено автор J_mie6, источник
@leftaroundabout I' d не соглашаются на самом деле. I' d говорят, что хвостовая рекурсия более ограничивается, чем goto, учитывая потребность подскочить к себе и только в положении хвоста. Это существенно эквивалентно конструкции перекручивания. I' d говорят, что рекурсия в целом эквивалентна, чтобы GOTO . В любом случае, когда вы собираете хвостовую рекурсию, она главным образом просто сводится к , в то время как (верный) петля с телом функции в том, где раннее возвращение - просто разрыв заявление. Сгиб, пока вы правильны об этом являющийся петлей, на самом деле более ограничивается, чем общая конструкция перекручивания; это больше похоже на цикл foreach
добавлено автор J_mie6, источник

Мне действительно нравится Ответ в июлях, но я хотел дополнительно указать на что-то, что люди часто пропускают о ленивом функциональном программировании, которое является, что все не должно быть "в петле". Например:

baseSums = scanl (+) 0

offsets = scanl (\offset sum -> if sum == 150 then offset + 100 else offset) 0

zipWithOffsets xs = zipWith (+) xs (offsets xs)

stopAt10 xs = if 10 `elem` xs then 10 else last xs

result = stopAt10 . zipWithOffsets . baseSums

result [1..]         -- 10
result [11..1000000] -- 500000499945

Вы видите, что каждая часть вашей логики может быть вычислена в отдельной функции, тогда составленной вместе. Это допускает меньшие функции, которые обычно намного легче расследовать. Для вашего игрушечного примера возможно это добавляет больше сложности, чем это удаляет, но в реальном мире кодируют разделение, обособленно функционирует, часто намного более просты, чем целое.

12
добавлено
логика рассеяна на всем протяжении здесь. этот код won' t быть легким поддержать. stopAt10 не хороший потребитель. ваш ответ лучше, чем тот, который вы цитируете, в котором это правильно изолирует основного производителя scanl (+) 0 ценностей. их потребление должно включить управляющую логику непосредственно, хотя, лучше осуществляется со всего два промежуток s и в последний раз , явно. это тесно следовало бы за оригинальной кодовой структурой и логикой, также, и было бы легко поддержать.
добавлено автор Rex Space, источник

Большинство примеров обработки списков вы будете видеть функции использования как карта , фильтр , сумма и т.д., которые воздействуют на список в целом. Но в вашем случае у вас есть условный ранний выход - довольно необычный образец, который не поддерживается обычными операциями по списку. Таким образом, необходимо уронить уровень абстракции и рекурсию использования - который также ближе к тому, как обязательный пример смотрит.

Это довольно прямое (вероятно, не идиоматичный) перевод на Clojure:

(defn doSomeCalc 
  ([lst] (doSomeCalc lst 0))
  ([lst sum]
    (if (empty? lst) sum
        (if (= sum 10) sum
            (let [sum (+ sum (first lst))]
                 [sum (if (= sum 150) (+ sum 100) sum)]
               (recur (rest lst) sum))))))) 

Править: Жюль указывает, что уменьшает в Clojure делают , поддерживают ранний выход. Используя это более изящно:

(defn doSomeCalc [lst]  
  (reduce (fn [sum val]
    (if (= sum 10) (reduced sum)
        (let [sum (+ sum val)]
             [sum (if (= sum 150) (+ sum 100) sum)]
           sum))
   lst)))

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

6
добавлено
@Jules: Прохладный - который является, вероятно, более идиоматическим решением.
добавлено автор JacquesB, источник
@jcast - в то время как takeWhile является общей операцией, это isn' t особенно полезный в этом случае, потому что вам нужны результаты вашего преобразования, прежде чем можно будет решить, остановиться ли. На ленивом языке этот doesn' t вопрос: можно использовать просмотр и takeWhile на результатах просмотра (см. Карла Bielefeldt' s ответ, который, в то время как это doesn' t использование takeWhile мог легко быть переписан, чтобы сделать так), но для строгого языка как clojure это будет означать обрабатывать весь список и затем отказываться от результатов впоследствии. Функции генератора могли решить это, однако, и я полагаю, что clojure поддерживает их.
добавлено автор Jules, источник
посмотрите редактировать, я просто добавил к своему ответу: Clojure' s уменьшают , операция поддерживает ранний выход.
добавлено автор Jules, источник
Неправильный - или takeWhile не ' общий operation'?
добавлено автор John Washburn, источник
@Jules берут - в то время как в Clojure производит ленивую последовательность (по словам докторов). Другой способ заняться этим был бы с преобразователи (возможно, лучший).
добавлено автор Rex Space, источник

Как указано другими ответами, Clojure имеет уменьшенный для остановки сокращений рано:

(defn some-calc [coll]
  (reduce (fn [answer e]
            (let [answer (+ answer e)]
               (case answer
                 10  (reduced answer)
                 150 (+ answer 100)
                 answer)))
          0 coll))

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

Продолжения спасения - обобщенная версия разрыва и возвращения заявления. Они непосредственно осуществляются в некоторых Схемах ( требование с продолжением спасения ), язык Common LISP ( блок + возвращение , выгода + бросок ) и даже C ( setjmp + longjmp ). Более общие разграниченные или неразграниченные продолжения, как найдено в стандартной Схеме или как монады продолжения в Хаскелле и Скале могут также использоваться в качестве продолжений спасения.

Например, в Ракетке вы могли использовать , позволяют/ЕС как это:

(define (some-calc ls)
  (let/ec break ; let break be an escape continuation
    (foldl (lambda (answer e)
             (let ([answer (+ answer e)])
               (case answer
                 [(10)  (break answer)] ; return answer immediately
                 [(150) (+ answer 100)]
                 [else  answer])))
           0 ls)))

У многих других языков также есть продолжение спасения - как конструкции в форме обработки исключений. В Хаскелле вы могли также использовать одну из различных ошибочных монад с foldM . Поскольку они - прежде всего, конструкции обработки ошибок, используя исключения, или ошибочные монады для ранней прибыли обычно культурно недопустимое и возможно довольно медленный.

Можно также опуститься от функций высшего порядка до последних вызовов.

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

(defn some-calc [coll]
  (loop [answer 0, [e es :as coll] coll]
    (if (empty? coll)
      answer
      (let [answer (+ answer e)]
        (case answer
          10 answer
          150 (recur (+ answer 100) es)
          (recur answer es))))))
3
добавлено
Ре используя ошибочные монады в Хаскелле, я don' t полагают, что здесь есть любая реальная потеря производительности. Они имеют тенденцию думаться вроде обработки исключений, но их don' t работают тот же самый путь и там isn' t любой требуемый проход по стеку, поэтому действительно shouldn' t быть проблемой, если используется этот путь. Кроме того, даже если there' s культурная причина не использовать чему-то нравится MonadError , в основном эквивалентное , у Любого нет такого уклона к только обработке ошибок, так может легко использоваться в качестве замены.
добавлено автор Jules, источник
@Jules, который я думаю, возвращая Левый, не препятствует тому, чтобы сгиб посетил весь список (или другая последовательность). Не глубоко знакомый с внутренностями библиотеки стандарта Хаскелла все же.
добавлено автор Nachiket Mehta, источник

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

Вот функциональное внедрение общей петли:

loop : v -> (v -> v) -> (v -> Bool) -> v
loop init iter cond_to_cont = 
    if cond_to_cont init 
        then loop (iter init) iter cond
        else init

Это берет (начальное значение переменной цикла, функция, которая выражает единственное повторение [на переменной цикла]) (условие продолжить петлю).

Ваш пример использует петлю на множестве, которое также ломается. Эта способность на вашем императивном языке испеклась на сам язык. В функциональном программировании такая способность обычно осуществляется на уровне библиотеки. Вот возможное внедрение

module Array (foldlc) where

foldlc : v -> (v -> e -> v) -> (v -> Bool) -> Array e -> v
foldlc init iter cond_to_cont arr = 
    loop 
        (init, 0)
        (λ (val, next_pos) -> (iter val (at next_pos arr), next_pos + 1))
        (λ (val, next_pos) -> and (cond_to_cont val) (next_pos < size arr))

В нем:

Я использую ((val, next_pos)) пара, которая содержит переменную цикла, видимую снаружи и положение во множестве, которое скрывает эта функция.

Итеративная функция немного более сложна, чем в общей петле, эта версия позволяет использовать текущий элемент множества. [Это находится в с приправой карри форма.]

Такие функции обычно называют "сгибом".

Я поместил "l" в имя, чтобы указать, что накопление элементов множества сделано левоассоциативным способом; подражать привычке к императивным языкам программирования повторить множество от низко до высокого индекса.

Я поместил "c" в имя, чтобы указать, что эта версия сгиба берет условие, которое управляет если и когда петля, которая будет остановлена рано.

Конечно, такие сервисные функции, вероятно, будут легко доступны в основной библиотеке, отправленной с используемым языком функционального программирования. Я написал им здесь для демонстрации.

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

Переменная в вашей петле - пара ('ответ', булево, которое кодирует, продолжить ли).

iter : (Int, Bool) -> Int -> (Int, Bool)
iter (answer, cont) collection_element = 
  let new_answer = answer + collection_element
  in case new_answer of
    10 -> (new_answer, false)
    150 -> (new_answer + 100, true)
    _ -> (new_answer, true)

Обратите внимание, что я использовал новую "переменную" 'new_answer'. Это вызвано тем, что в функциональном программировании я не могу изменить ценность уже инициализированной "переменной". Я не волнуюсь о работе, компилятор может добраться, чтобы снова использовать память об 'ответе' для 'new_answer' через пожизненный анализ, если это думает, что это более эффективно.

Слияние этого в нашу функцию петли, развитую ранее:

doSomeCalc :: Array Int -> Int
doSomeCalc arr = fst (Array.foldlc (0, true) iter snd arr)

"Множество" здесь - имя модуля, которое экспортирует функцию foldlc.

"кулак", "второй" стенд для функций, который возвращает первый, второй компонент его параметра пары

fst : (x, y) -> x
snd : (x, y) -> y

В этом случае стиль "без пунктов" увеличивает удобочитаемость внедрения doSomeCalc:

doSomeCalc = Array.foldlc (0, true) iter snd >>> fst

(>>>) is function composition : (>>>) : (a -> b) -> (b -> c) -> (a -> c)

Это совпадает с выше, просто параметр "прибытия" оставляют из обеих сторон уравнения определения.

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

2
добавлено
pro.jvm
pro.jvm
3 503 участник(ов)

Сообщество разработчиков Java Scala Kotlin Groovy Clojure Чат для нач-их: @javastart Наш сайт: projvm.com projvm.ru Наш канал: @proJVM Вакансии: @jvmjobs Конфы: @jvmconf

Haskell
Haskell
910 участник(ов)

https://combot.org/chat/-1001043143583 Ссылки на полезные ресурсы: https://ruhaskell.org/links.html ;

Clojure — русскоговорящее сообщество
Clojure — русскоговорящее сообщество
433 участник(ов)

Общаемся на темы, посвященный Clojure. Решаем проблемы, обмениваемся опытом и делимся новостями. Вакансии и поиск работы: @clojure_jobs Вам могут быть интересны: @javascript_ru, @nodejs_ru, @ruby_ru, @devops_ru, @devops_jobs

ФП
ФП
179 участник(ов)

Все о функциональных языках