Re[4]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 01.12.09 10:20
Оценка: 15 (4) +2
Здравствуйте, Mr.Cat, Вы писали:

MC>Здравствуйте, Gaperton, Вы писали:

G>>1) Методы, и "ортогональность" типов и методов.
MC>Не совсем понимаю, что ты имеешь в виду. То, что есть типы данных, а у них есть методы? Да, в лимбо так вроде бы.

В Go метод можно прицепить в к любому типу, кроме интерфейса. Можно к массиву. Можно к инту. А можно —

type SecsSince1900 int

Вот к этому. Или —

type SomeShit [][]SecsSince1900

К этому.

Это есть "ортогональность" — типы отдельно, методы отдельно. Чрезвычайно занимательное свойство, и синтаксис языка тут не причем. Это было в лимбе?

Смотри еще как можно делать в Go. Если ты напишешь

type LocalTime struct {
SecsSince1900 // указали тип, но не указали имени члена структуры
zone TimeZone
}

То все методы, которые связанны с типом SecsSince1900 перейдут к типу LocalTime. Ну очень любопытное свойство. Наследование, в таком интересном виде, в виде слегонца "подсахаренной" агрегации, пнимаете-ли . Просто и симпатично. Так можно делать в лимбе?

G>>2) Интерфейсы, и "утиная типизация"

MC>Тут в limbo по-другому. В limbo под интерфейсом понимается интерфейс модуля: функции и типы данных, им экспортируемые. Соответственно, у одного интерфейса модуля могут быть разные реализации. В go, конечно, поинтереснее сделано.

В лимбе сделано более-менее прямолинейно. Так много кто делал и делает.

А в Го — интерфейсы "ортогональны" и методам, и типам. Их суть — они добавляют полиморфизм и динамическую диспетчеризацию вызова (вызов метода у интерфейса является "виртуальным"). Причем, связывание типа с интерфейсом происходит автоматически, без лишних телодвижений. Методов у типа хватает — он соответствует интерфейсу.

Теперь, имея эту ортогональную тройку (типы-методы-интерфейсы), посмотри на это дело вот с какой стороны. Пустому интерфейсу interface{}, в котором нет методов, автоматически соответствует вообще любой тип языка. Все не есть Object, но, без дураков, все есть interface{}, прозрачно и автоматически.

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

А схожесть синтаксиса — это ерунда. Главное, что отличает языки друг от друга — это система типов.
Re[15]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 03.12.09 10:03
Оценка: +1
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Можно, конечно. Только смущает ограничение на количество потоков ОС.


А также их дороговизна. Большое время создания, переключения контекста, взаимодействия, итд.
Re[13]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 03.12.09 10:09
Оценка: 5 (2)
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Это всё называется workarounds, а Эрланг мне не очень нравится из-за быстродействия. Кстати говоря, я не имел в виду кооперативную многозадачность.


С реальным быстродействием у Эрланга все не так плохо. То есть, рантайм, конечно, медленный, если на микротестах сравнивать. Но в жизни все сложнее.
http://www.slideshare.net/Arbow/comparing-cpp-and-erlang-for-motorola-telecoms-software

Этот отчет крайне любопытен, взгляни. Один из аспектов поведения программ на Эрланге, недостижимый на данный момент на других платформах — repeated failure (один из клиентов долбится на сервер и вызывает креш) не приводит к снижению пропускной способности как отдельного сервера, так и фермы. Из-за одного этого достаточно большая ферма в реальных условиях будет работать быстрее во многих случаях, чем аналогичная на С/С++.

Не говоря уже о понижении severity багов, ради чего можно и серверов на ферму подбросить. Скорость не имеет такого значения в наше время, как масштабируемость.
Re[13]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 03.12.09 10:13
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Это всё называется workarounds, а Эрланг мне не очень нравится из-за быстродействия. Кстати говоря, я не имел в виду кооперативную многозадачность.


Медиакодеки, впрочем, и прочий numbercrunching (небольшие, относительно простые программы, жующие большой объем данных), делать на Эрланге — больная идея. Это надо писать на С/С++ и подцеплять к управляющей логике на Эрланге. Преимущество Go может быть в том, что он позволит избежать вот таких многоязычных связок. Но пока — это не так, и он почти такой же тормозной, как Эрланг. Надо подождать полгода-год.
Re[4]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 03.12.09 23:00
Оценка: 16 (3)
Здравствуйте, Mr.Cat, Вы писали:

Черт возьми, я люблю этот язык . Смотри:

type Lazy interface { force() Lazy }

func ( computation func() Lazy ) force() Lazy { return computation() }


Ты видишь, что произошло? Я выше сделал объявление, что любая функция без аргументов, возвращающая Lazy, является самым настоящим, первоклассным объектом, реализующим интерфейс Lazy С ума сойти можно .
Re[5]: [ANN] 12 Things to Know About Google's Go
От: vdimas Россия  
Дата: 03.12.09 23:39
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Теперь, имея эту ортогональную тройку (типы-методы-интерфейсы), посмотри на это дело вот с какой стороны. Пустому интерфейсу interface{}, в котором нет методов, автоматически соответствует вообще любой тип языка. Все не есть Object, но, без дураков, все есть interface{}, прозрачно и автоматически.


Может это и не принципиально, насчет пустого interface{}, но вот "строгая утиная типизация" (оксюморон), это то, чего мне всегда не хватало, когда писал т.н. "бизнес-логику". Ибо городить и поддерживать иерархию взаимодействующих интерфейсов и реализующих их классов в современных main stream языках — это убогий процесс разработки, просто гири на ногах, т.к. на лицо непомерная цена самых простых изменений интерфейсов, вызывающая по цепочке изменения реализаций. Если одно от другого отвязать, процесс прототипирования сольется с процессом целевой разработки, как в некоторых языках/средах.

G>А в Го — интерфейсы "ортогональны" и методам, и типам. Их суть — они добавляют полиморфизм и динамическую диспетчеризацию вызова (вызов метода у интерфейса является "виртуальным"). Причем, связывание типа с интерфейсом происходит автоматически, без лишних телодвижений. Методов у типа хватает — он соответствует интерфейсу.


Вот интересно, насколько получится эффективно. А то нечто похожее в VB всегда было (если отбросить явное приведение к интерфейсу).
Re[5]: [ANN] 12 Things to Know About Google's Go
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 04.12.09 02:16
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Это есть "ортогональность" — типы отдельно, методы отдельно. Чрезвычайно занимательное свойство, и синтаксис языка тут не причем.


Правда, тут есть ложка дёгтя — о защищённости данных можно забыть. Хотя, конечно, можно интерфейсами обыграть.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[5]: [ANN] 12 Things to Know About Google's Go
От: WolfHound  
Дата: 04.12.09 09:13
Оценка: +1
Здравствуйте, Gaperton, Вы писали:

G>Ты видишь, что произошло? Я выше сделал объявление, что любая функция без аргументов, возвращающая Lazy, является самым настоящим, первоклассным объектом, реализующим интерфейс Lazy

Осталось понять нафига это нужно.
Также не ясно сколько раз нужно будет дернуть force чтобы таки вычислить выражение. Ибо computation может вернуть как вычисленное значение так и еще один computation. Кстати для всех значений также придется реализовать интерфейс Lazy.
И самое противное что даже если мы таки узнаем когда значение вычислилось то для того чтобы им воспользоваться нам придется приводить к нужному нам типу явно.
Короче мягко говоря многовато грязи и неопределенности для первоклассного объекта.

G>С ума сойти можно .

Угу. Отличный способ шифрования кода.
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[6]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 04.12.09 17:32
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Осталось понять нафига это нужно.


Ну мне например уже понятно, зачем это может быть нужно.

Для мягкого сочетания функционального и объектного стилей. Когда требуется состояние — даешь объект. Когда его не требуется — даешь функцию. Примеров полезного применения данной возможности может быть масса. Простейший:

type Transformer interface{ transform( iterface{} ) interface{} }
type Iterable interface{
   next() (Iterable, bool)
   is_valid() bool
}

func for_each( t Transformer, it Iterable ) {
   for it.is_valid() {
      it = t( current )
      it.next()
   }
}

func ( t func( interface{} ) interface{} ) transform( value interface{} ) interface{} {
   return t( value )
}


Вот таким образом определенный for_each позволяет брать аргументом как простую функцию, так и объект. Мы можем протянуть состояние от вызова к вызову при желании — примерно так же, как с "функтором" в С++. Только здесь:
1) в отличии от С++, все будет работать в динамике
2) по причине наличия замыканий — не надо городить лишнего мусора, как в С++.
3) Данная техника подойдет для реализации ленивых вычислений и структур. Которые проще застрелиться, чем прилично изобразить в С++
4) Насчет отсутствия дженериков, и влияния этого факта на пример — не переживай. дженерики на подходе.

И это только один пример. То, что в С++ встроено в язык (функторы), здесь является одним из частных случаев системы типов.

WH>Также не ясно сколько раз нужно будет дернуть force чтобы таки вычислить выражение. Ибо computation может вернуть как вычисленное значение так и еще один computation. Кстати для всех значений также придется реализовать интерфейс Lazy.


Ясно. Один раз. Реализовать его надо не для всех значений, а только для ленивых. Это делается в одну строку для любого типа. И будет явным указанием на то, что этот тип "ленив".

WH>И самое противное что даже если мы таки узнаем когда значение вычислилось то для того чтобы им воспользоваться нам придется приводить к нужному нам типу явно.


value.force()(.нужный_тип)

Это далеко не самое противное (к тому же, вылечится добавлением генериков). Будет гораздо противное, когда ты попытаешься сделать ленивый список в С++ или Java.

WH>Короче мягко говоря многовато грязи и неопределенности для первоклассного объекта.


Не, не многовато.

G>>С ума сойти можно .

WH>Угу. Отличный способ шифрования кода.

Отличный способ шифрования кода — это перекрытые операторы, которые тебе так нравятся. А здесь все прозрачно.
Re[6]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 04.12.09 17:33
Оценка: :)
Здравствуйте, Геннадий Васильев, Вы писали:

G>>Это есть "ортогональность" — типы отдельно, методы отдельно. Чрезвычайно занимательное свойство, и синтаксис языка тут не причем.


ГВ>Правда, тут есть ложка дёгтя — о защищённости данных можно забыть. Хотя, конечно, можно интерфейсами обыграть.


Защищенность данных есть иллюзия.

#define private public
#include "uber_mega_protected_data.h"



Но если про нее не забывать — в Go положено это делать интерфейсами.
Re[6]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 04.12.09 17:35
Оценка:
Здравствуйте, vdimas, Вы писали:

G>>А в Го — интерфейсы "ортогональны" и методам, и типам. Их суть — они добавляют полиморфизм и динамическую диспетчеризацию вызова (вызов метода у интерфейса является "виртуальным"). Причем, связывание типа с интерфейсом происходит автоматически, без лишних телодвижений. Методов у типа хватает — он соответствует интерфейсу.


V>Вот интересно, насколько получится эффективно. А то нечто похожее в VB всегда было (если отбросить явное приведение к интерфейсу).


Вызов метода интерфейса — это самый обычный "виртуальный" вызов .
Re[7]: [ANN] 12 Things to Know About Google's Go
От: WolfHound  
Дата: 04.12.09 18:25
Оценка:
Здравствуйте, Gaperton, Вы писали:

G>Для мягкого сочетания функционального и объектного стилей. Когда требуется состояние — даешь объект. Когда его не требуется — даешь функцию. Примеров полезного применения данной возможности может быть масса. Простейший:

1)Где в твоем примере Lazy?
2)Твой пример не имеет практического применения ибо на практике интерфейс Transformer можно реализовать только для функции ибо если его реализовать для объекта то в одном месте нам может понадобиться одна реализация, а в другом другая и как следствие придется городить функцию.

G>1) в отличии от С++, все будет работать в динамике

Это минус.

G>2) по причине наличия замыканий — не надо городить лишнего мусора, как в С++.

Это хорошо но если вспомнить что не С++ом единым то...

G>3) Данная техника подойдет для реализации ленивых вычислений и структур. Которые проще застрелиться, чем прилично изобразить в С++

Если сравнивать с С++ то почти любой язык будет конфеткой.

G>4) Насчет отсутствия дженериков, и влияния этого факта на пример — не переживай. дженерики на подходе.

Посмотрим что у них получиться. Ибо генерики тоже можно реализовать не правильно.

G>Ясно. Один раз.

А если computation вернет computation?

G>Реализовать его надо не для всех значений, а только для ленивых. Это делается в одну строку для любого типа. И будет явным указанием на то, что этот тип "ленив".

Те для всех которые может возвращать computation.
Еще вопрос где и когда помечать типы ленивыми. Ибо у нас может возникнуть проблема что тип пометят ленивым в нескольких модулях...

G>value.force()(.нужный_тип)

Вместо просто value.

G>Это далеко не самое противное (к тому же, вылечится добавлением генериков). Будет гораздо противное, когда ты попытаешься сделать ленивый список в С++ или Java.

А можно я это на немерле сделаю? http://nemerle.org/Lazy_evaluation

WH>>Короче мягко говоря многовато грязи и неопределенности для первоклассного объекта.

G>Не, не многовато.
Многовато даже по сравнению с немерлом куда это пришлось встраивать. А если сравнивать с языком где лень есть на уровне системы типов...

G>Отличный способ шифрования кода — это перекрытые операторы, которые тебе так нравятся. А здесь все прозрачно.

Те ты готов отказаться от операторов для арифметических выражений? Или для операций над int'ами и float'ами использовать разные операторы?
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[8]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 05.12.09 15:59
Оценка:
Здравствуйте, WolfHound, Вы писали:

G>>Для мягкого сочетания функционального и объектного стилей. Когда требуется состояние — даешь объект. Когда его не требуется — даешь функцию. Примеров полезного применения данной возможности может быть масса. Простейший:

WH>1)Где в твоем примере Lazy?

Я достаточно внятно объяснил все в абзаце выше.

WH>2)Твой пример не имеет практического применения ибо на практике интерфейс Transformer можно реализовать только для функции ибо если его реализовать для объекта то в одном месте нам может понадобиться одна реализация, а в другом другая и как следствие придется городить функцию.


Во-первых, такого типа как "объект" в Go нет, во-вторых — этот интерфейс одинаково реализуется для любого типа данных, нет совершенно никакой разницы. Например:

type adder int
interface {} ( x adder ) transform( value interface{} ) { return x + value(.int) }

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

G>>1) в отличии от С++, все будет работать в динамике

WH>Это минус.
Это плюс.

G>>2) по причине наличия замыканий — не надо городить лишнего мусора, как в С++.

WH>Это хорошо но если вспомнить что не С++ом единым то...

Мало-ли что можно не к месту вспомнить. Я в посте говорю о функциях как объектах, и о том, как это делается в Go. У тебя есть, что сказать по существу — говори.

G>>3) Данная техника подойдет для реализации ленивых вычислений и структур. Которые проще застрелиться, чем прилично изобразить в С++

WH>Если сравнивать с С++ то почти любой язык будет конфеткой.

Не будет.

G>>4) Насчет отсутствия дженериков, и влияния этого факта на пример — не переживай. дженерики на подходе.

WH>Посмотрим что у них получиться. Ибо генерики тоже можно реализовать не правильно.

Посмотрим. Можно.

G>>Ясно. Один раз.

WH>А если computation вернет computation?

То будет ошибка.

G>>Реализовать его надо не для всех значений, а только для ленивых. Это делается в одну строку для любого типа. И будет явным указанием на то, что этот тип "ленив".

WH>Те для всех которые может возвращать computation.

type LazyValue interface {
    force() interface{}
}


А теперь? Если тебя так волнует именно ленивость, то так более правильно.

WH>Еще вопрос где и когда помечать типы ленивыми. Ибо у нас может возникнуть проблема что тип пометят ленивым в нескольких модулях...


В том месте, где тип определяется.

G>>value.force()(.нужный_тип)

WH>Вместо просто value.

Я уже сказал что я по этому поводу думаю — небольшая проблема.

G>>Это далеко не самое противное (к тому же, вылечится добавлением генериков). Будет гораздо противное, когда ты попытаешься сделать ленивый список в С++ или Java.

WH>А можно я это на немерле сделаю? http://nemerle.org/Lazy_evaluation

Делай хоть на брейнфаке, я не против.

WH>>>Короче мягко говоря многовато грязи и неопределенности для первоклассного объекта.

G>>Не, не многовато.
WH>Многовато даже по сравнению с немерлом куда это пришлось встраивать. А если сравнивать с языком где лень есть на уровне системы типов...

Для языка, где лени нет на уровне системы типов, и где нет макросов — не многовато. А именно таким языком и является Go.

G>>Отличный способ шифрования кода — это перекрытые операторы, которые тебе так нравятся. А здесь все прозрачно.

WH>Те ты готов отказаться от операторов для арифметических выражений? Или для операций над int'ами и float'ами использовать разные операторы?

Я тебе достаточно подробно объяснил в прошлый раз, почему я так считаю. Не вижу смысла это мусолить.
Re[6]: [ANN] 12 Things to Know About Google's Go
От: Gaperton http://gaperton.livejournal.com
Дата: 05.12.09 16:18
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Вот интересно, насколько получится эффективно. А то нечто похожее в VB всегда было (если отбросить явное приведение к интерфейсу).


Кстати, действительно во многом похоже на модель COM и VB. Только в COM с VB не было "ортогональности" и "утиности". А эти вещи очень существенны. Они, я бы сказал, являются определяющим отличием.
Re[9]: [ANN] 12 Things to Know About Google's Go
От: WolfHound  
Дата: 05.12.09 18:32
Оценка: :)
Здравствуйте, Gaperton, Вы писали:

G>type adder int

G>interface {} ( x adder ) transform( value interface{} ) { return x + value(.int) }
Это вместо простого и понятного x + _ ?
Замечательный язык.

G>В третьих, чтобы судить о практическом применении того или иного приема в некотором языке, надо дать себе труд с языком ознакомиться. Тебе пока судить об этом рановато.

Я ознакомился.
А еще я ознакомился с еще кучей языков.
И для того чтобы понять что язык отстой мне достаточно посмотреть доки по диагонали.

G>>>1) в отличии от С++, все будет работать в динамике

WH>>Это минус.
G>Это плюс.
Проверки времени исполнения там где их можно легко избежать всегда минус.

G>Мало-ли что можно не к месту вспомнить.

Вот и не вспоминай С++ не к месту.

G>Я в посте говорю о функциях как объектах, и о том, как это делается в Go. У тебя есть, что сказать по существу — говори.

Функции как объекты не нужны.
Вообще не нужны.
Замыканий которые могут захватывать изменяемые данные более чем достаточно.

G>>>Ясно. Один раз.

WH>>А если computation вернет computation?
G>То будет ошибка.
Когда?

G>
G>type LazyValue interface {
G>    force() interface{}
G>} 
G>

G>А теперь? Если тебя так волнует именно ленивость, то так более правильно.
Теперь мне совсем не ясно чем оно лучше просто функции.

WH>>Еще вопрос где и когда помечать типы ленивыми. Ибо у нас может возникнуть проблема что тип пометят ленивым в нескольких модулях...

G>В том месте, где тип определяется.
А если тип в чужом коде который по какимто причинам нельзя править?

G>>>value.force()(.нужный_тип)

WH>>Вместо просто value.
G>Я уже сказал что я по этому поводу думаю — небольшая проблема.
Я еще могу понять любителей всяких питонов где есть кучу проверок во время исполнения но у нах хоть код чистый.
А тут и проверки времени исполнения и грязь в коде.
А если вспомнить немерле и скалу то становится вообще не понятно как можно называть го хорошим языком.

G>>>Это далеко не самое противное (к тому же, вылечится добавлением генериков). Будет гораздо противное, когда ты попытаешься сделать ленивый список в С++ или Java.

WH>>А можно я это на немерле сделаю? http://nemerle.org/Lazy_evaluation
G>Делай хоть на брейнфаке, я не против.
Очередной слив засчитан.
Ибо как только в сравнении с го появляются нормальные языки, а не старый хлам ты прячешь голову в песок.

G>Для языка, где лени нет на уровне системы типов, и где нет макросов — не многовато. А именно таким языком и является Go.

Оно даже на С++ лучше получается
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/variant.hpp>

template<class Result>
class LazyValue
{
public:
    LazyValue(boost::function<Result()> fn)
        : holder_(fn)
    {}

    operator Result()
    {
        if (Result* res = boost::get<Result>(&holder_))
        {
            return *res;
        }
        else
        {
            boost::function<Result()> fn = boost::get<boost::function<Result()> >(holder_);
            Result r = fn();
            holder_ = r;
            return r;
        }
    }

private:
    boost::variant<Result, boost::function<Result()> > holder_;
};

int fn(int i)
{
    std::cout << "call" << std::endl;
    return i;
}

void print(LazyValue<int> val)
{
    std::cout << "print 1" << std::endl;
    std::cout << val << std::endl;
    std::cout << val << std::endl;
    std::cout << val << std::endl;
    std::cout << "print 2" << std::endl;
}

int main()
{
    LazyValue<int> val(boost::bind(fn, 10));
    std::cout << "---====1===---" << std::endl;
    print(val);
    std::cout << "---====2===---" << std::endl;
    return 0;


G>Я тебе достаточно подробно объяснил в прошлый раз, почему я так считаю. Не вижу смысла это мусолить.

В прошлый раз ты молча слил переведя все свое внимание на обсуждение LINQ который тебе был якобы не интересен
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[10]: [ANN] 12 Things to Know About Google's Go
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 06.12.09 14:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

G>>Я в посте говорю о функциях как объектах, и о том, как это делается в Go. У тебя есть, что сказать по существу — говори.

WH>Функции как объекты не нужны.
WH>Вообще не нужны.
WH>Замыканий которые могут захватывать изменяемые данные более чем достаточно.

Вероятно ты это писал не всерьёз, на счет функции как объекты.
Re[11]: [ANN] 12 Things to Know About Google's Go
От: WolfHound  
Дата: 06.12.09 16:22
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Вероятно ты это писал не всерьёз, на счет функции как объекты.

Я вот про это извращение.
type Transformer interface{ transform( iterface{} ) interface{} }
type Iterable interface{
   next() (Iterable, bool)
   is_valid() bool
}

func for_each( t Transformer, it Iterable ) {
   for it.is_valid() {
      it = t( current )
      it.next()
   }
}

func ( t func( interface{} ) interface{} ) transform( value interface{} ) interface{} {
   return t( value )
}

И я обсолютно серьезно.
Извращения со всякими Transformer'ами при наличии первокласных функций не нужны.
... << RSDN@Home 1.2.0 alpha 4 rev. 1305>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.