Синтаксис Scala Vector fold (/: и :\ и /:\)

Может ли кто-нибудь привести несколько примеров того, как

/: :\ и /:\

Реально привыкнуть? Я предполагаю, что это ярлыки для методов уменьшения/свертывания, но в документах Scala нет примеров того, как они на самом деле используются, и их невозможно найти в Google/искать в StackOverflow.


person chbrown    schedule 07.09.2011    source источник
comment
Также известен как сгиб влево (foldl), сгиб вправо (foldr) и сгиб в любом месте (??). В Википедии есть некоторая общая информация и красивые картинки о сгибах.   -  person    schedule 07.09.2011


Ответы (3)


/: является синонимом foldLeft и :\ для foldRight.

Но помните, что : заставляет /: применяться к объекту справа от него.

Предполагая, что вы знаете, что (_ * _) — это анонимная функция, эквивалентная (a, b) => a * b, а сигнатура foldLeft и foldRight — это

def foldLeft  [B] (z: B)(f: (B, A) ⇒ B): B 
def foldRight [B] (z: B)(f: (A, B) ⇒ B): B 

то есть это каррированные функции, принимающие начальное значение, и функция, объединяющая начальное значение/аккумулятор с элементом из списка, некоторые примеры:

List(1,2,3).foldLeft(1)(_*_)

что то же самое, что

(1 /: List(1,2,3))(_*_)

И

List(1,2,3).foldRight(1)(_*_)

в инфиксной записи

(List(1,2,3) foldRight 1)(_*_)

что то же самое, что

(List(1,2,3) :\ 1)(_*_)

Добавляйте свои собственные коллекции и функции и наслаждайтесь!

Что нужно помнить с короткими (/: и :\) нотациями, так это то, что, поскольку вы используете инфиксные нотации, вам нужно заключать в скобки первую часть, чтобы она могла правильно подобрать второй список аргументов. Кроме того, помните, что функции для foldLeft и foldRight противоположны, но это имеет смысл, если вы визуализируете складку в уме.

person Luigi Plinge    schedule 07.09.2011
comment
Забыл сказать, /:\ — это синоним fold, то есть сворачивания, когда вам не важен порядок. Синтаксис такой же, как и для :\ . Я никогда не использовал его, но я думаю, что это полезно для параллельных коллекций, так что вы можете разделить операцию сворачивания между несколькими потоками/актерами. - person Luigi Plinge; 08.09.2011

Лично я предпочитаю /: и :\ формы foldLeft и foldRight. Две причины:

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

    (1 /: ints) { _ + _ }
    
    ints.foldLeft(1) { _ + _ }
    

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

  2. Порядок параметров Function2 такой же, как у свернутого элемента и того, в который складывается:

       (b /: as) { (bb, a) => f(bb, a) }
     // ^    ^      ^   ^
     // ^    ^      ^   ^
     // B    A      B   A
    

    Лучше во всех отношениях, чем:

    as.foldLeft(b) { (bb, a) => f(bb, a) }
    

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

Я надеюсь, что также должно быть очевидно, как :\ работает с foldRight - это в основном то же самое, за исключением того, что значение, кажется, вставляется с правой стороны. Должен сказать, что я стараюсь держаться подальше от foldRight в scala из-за того, как он реализован (то есть неправильно).

person oxbow_lakes    schedule 07.09.2011
comment
Вы убедили меня. Я перехожу на /: с этого момента. - person Jon Shea; 08.09.2011

Рекс Керр написал хороший ответ о сгибах здесь. Ближе к концу вы можете увидеть пример синтаксиса быстрого доступа foldLeft и foldRight.

person om-nom-nom    schedule 07.09.2011