Языки, которые доводят цепочку до крайности? - PullRequest
1 голос
/ 26 ноября 2010

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

i(h(g(f(x))))

И вам придется читать это справа налево или от самого внутреннего довнешний больше всего.Сначала вы применяете f, затем g и так далее.Но если бы он был прикован цепью, он бы выглядел больше как

x|f|g|h|i

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


Из-за этого я обычно заканчиваю тем, что создаю целую кучу временных переменных, чтобы разделить их на отдельные строки и сделать их более читабельными:

a = f(x)
b = g(a)
c = h(b)
what_i_really_wanted_all_along = i(c)

Где с моим волшебным языком, вы все равно можете разбить его на разные строки, если они становятся слишком длинными, без необходимости использования промежуточных переменных:

x | f
  | g
  | h
  | i

Ответы [ 8 ]

5 голосов
/ 26 ноября 2010

Да, с F # у вас есть оператор конвейера |> (также называемый оператором прямой трубы, и у вас есть обратная труба <|).

Вы пишете это как: x |> f |> g |> h |> i

Проверьте это сообщение в блоге , которое дает хорошее представление об использовании в реальной жизни.

3 голосов
/ 26 ноября 2010

Ну, вы можете сделать это в JavaScript и его родственниках:

function compose()
{
    var funcs = Array.prototype.slice.call(arguments);
    return function(x)
    {
        var i = 0, len = funcs.length;
        while(i < len)
        {
            x = funcs[i].call(null, x);
            ++i;
        }
        return x;
    }
}

function doubleIt(x) { print('Doubling...'); return x * 2; }

function addTwo(x) { print('Adding 2...'); return x + 2; }

function tripleIt(x) { print('Tripling...'); return x * 3; }

var theAnswer = compose(doubleIt, addTwo, tripleIt)( 6 );
print( 'The answer is: ' + theAnswer );
// Prints:
//   Doubling...
//   Adding 2...
//   Tripling...
//   The answer is: 42

Как видите, функции читаются слева направо, и ни объект, ни функции не нуждаются в специальной реализации. Секрет всего в compose.

3 голосов
/ 26 ноября 2010

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

С одной стороны, любой язык с объектно-ориентированнымУ bent есть цепочка для методов, которые возвращают экземпляр класса:

obj.method1().method2().method3(); // JavaScript
MyClass->new()->f()->g()->i(); # Perl

С другой стороны, наиболее известным, хотя и наименее "языком программирования", примером этого шаблона цепочки будет что-то полностью не-OO ифункционал ... как вы уже догадались, трубы в Unix.Как и в ls | cut -c1-4 | sort -n.Поскольку программирование в оболочке считается языком, я говорю, что это вполне допустимый пример.

2 голосов
/ 27 ноября 2010

Методы расширения C # достигают чего-то очень близкого к вашему волшебному языку, если немного менее кратко:

x.f()
 .g()
 .h()
 .i();

Где методы объявляются таким образом:

static class Extensions 
{
    static T f<T>(this T x) { return x; }
    static T g<T>(this T x) { return x; }
    ...
}

Linq использует это оченьшироко.

2 голосов
/ 26 ноября 2010

То, что вы описываете - это, по сути, шаблон интерфейса Fluent.

В Википедии есть хороший пример из нескольких языков:

http://en.wikipedia.org/wiki/Fluent_interface

А у Мартина Фаулера есть его запись здесь:

http://www.martinfowler.com/bliki/FluentInterface.html

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

2 голосов
/ 26 ноября 2010

Haskell.Следующие три примера эквивалентны:

  • i(h(g(f(x)))) (вызовы вложенных функций)
  • x & f & g & h & i (цепочка слева направо по запросу)
  • (i . h . g . f)(x) (Композиция функций, более распространенная в Haskell)

http://www.haskell.org/haskellwiki/Function_composition

http://en.wikipedia.org/wiki/Function_composition_(computer_science)

1 голос
/ 03 декабря 2010

Как уже упоминалось ранее, Haskell поддерживает композицию функций следующим образом:

(i . h . g . f) x, что эквивалентно: i(h(g(f(x))))

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

infixr 1 >>>, <<<
(<<<) = (.) -- regular function composition
(>>>) = flip (.) -- flipped function composition

(f >>> g >>> h >>> i) x
    -- or --
(i <<< h <<< g <<< f) x

Это обозначение, используемое стандартной библиотекой Control.Category . (Хотя фактическая сигнатура типа обобщена и работает на другие вещи, кроме функций). Если вас все еще беспокоит то, что параметр находится в конце, вы также можете использовать вариант оператора приложения функции:

infixr 0 $
infixl 0 #
f $ x = f x -- regular function application
(%) = flip ($) -- flipped function application

i $ h $ g $ f $ x
    -- or --
x % f % g % h % i

Что близко к синтаксису, который вы хотите. Насколько мне известно, % НЕ является встроенным оператором в Haskell, но $ есть. Я замутил инфиксные биты. Если вам интересно, это техническая составляющая, которая делает приведенный выше код следующим:

(((x % f) % g) % h) % i -- intended

а не:

x % (f % (g % (h % i))) -- parse error (which then leads to type error)
1 голос
/ 26 ноября 2010

Я не предлагаю вам использовать Mathematica , если вы обычно не занимаетесь математикой, но она, безусловно, достаточно гибкая для поддержки записи Postfix.На самом деле, вы можете определить свои собственные обозначения, но давайте для простоты остановимся на Postfix.

Вы можете ввести:

Postfix[Sin[x]]

Для получения

x // Sin  

, что означает запись Postfix.Или, если у вас есть более глубокое выражение:

MapAll[Postfix, Cos[Sin[x]]]

Чтобы получить:

(Postfix[x]//Sin)//Cos  

Где вы можете увидеть Postfix [x] первым, как для Mathematica x - это выражение, которое будет оценено позже,

И наоборот, вы можете ввести:

x // Sin // Cos  

Чтобы получить, конечно,

Cos[Sin[x]]  

Или вы можете использовать очень часто используемую идиому,используйте Postfix в форме Postfix:

Cos[x] // Postfix

Чтобы получить

x // Cos

HTH!

Кстати: как ответ на вопрос Где мой магический язык?, смотрите это:

(x//Sin 
  // Cos
  // Exp 
  // Myfunct)  

дает

Myfunct[E^Cos[Sin[x]]]  

PS: В качестве упражнения для читателей :) ... Как это сделать для функций, которые принимают n переменных?

...