Pergunta

Eu não acho que eu grokked currying ainda. Eu entendo o que ele faz, e como fazê-lo. Eu só não consigo pensar em uma situação que eu iria utilizá-lo.

Onde você estiver usando currying em JavaScript (ou onde estão as principais bibliotecas de usá-lo)? manipulação ou de desenvolvimento de aplicação geral exemplos DOM bem-vindos.

Uma das respostas menciona animação. Funções como slideUp, fadeIn tomar um elemento como um argumentos e são normalmente uma função curry retornar a função de alta ordem com a “função de animação” default embutido. Por que isso é melhor do que apenas aplicando a função maior-up com alguns padrões?

Existem quaisquer desvantagens para usá-lo?

Conforme solicitado, aqui estão alguns bons recursos em JavaScript currying:

Vou acrescentar mais à medida que surgem nos comentários.


Assim, de acordo com as respostas, currying e aplicação parcial, em geral, são técnicas de conveniência.

Se você é freqüentemente “refino” uma função de alto nível, chamando-a com a mesma configuração, você pode caril (ou use parcial do Resig) a função de nível superior para criar simples, métodos concisa auxiliares.

Foi útil?

Solução

@Hank Gay

Em resposta ao comentário de EmbiggensTheMind:

Eu não consigo pensar em uma instância onde currying -de-se-é útil em JavaScript ; é uma técnica para converter chamadas de função com vários argumentos em cadeias de chamadas de função com um único argumento para cada chamada, mas JavaScript suporta vários argumentos em uma única chamada de função.

Em JavaScript, e eu presumo que a maioria outras línguas reais (não lambda cálculo) -é comumente associados à aplicação parcial, no entanto. John Resig explica isso melhor , mas a essência é que tem alguma lógica que será aplicado a dois ou mais argumentos, e você só sabe o valor (s) para alguns desses argumentos.

Você pode usar a aplicação parcial / currying para corrigir esses valores conhecidos e retornar uma função que só aceita as incógnitas, para ser chamado mais tarde, quando você realmente tem os valores que deseja passar. Isso fornece uma maneira bacana para evitar a repetição de si mesmo quando teria sido chamando o mesmo JavaScript built-ins mais e mais com os mesmos valores, mas um. Para roubar o exemplo de John:

String.prototype.csv = String.prototype.split.partial(/,\s*/);
var results = "John, Resig, Boston".csv();
alert( (results[1] == "Resig") + " The text values were split properly" );

Outras dicas

Aqui está um uso interessante e prático de currying em JavaScript que usa fechamentos :

function converter(toUnit, factor, offset, input) {
    offset = offset || 0;
    return [((offset + input) * factor).toFixed(2), toUnit].join(" ");
}

var milesToKm = converter.curry('km', 1.60936, undefined);
var poundsToKg = converter.curry('kg', 0.45460, undefined);
var farenheitToCelsius = converter.curry('degrees C', 0.5556, -32);

milesToKm(10);            // returns "16.09 km"
poundsToKg(2.5);          // returns "1.14 kg"
farenheitToCelsius(98);   // returns "36.67 degrees C"

Esta conta com uma extensão de curry de Function, embora, como você pode ver que só usa apply (nada muito extravagante):

Function.prototype.curry = function() {
    if (arguments.length < 1) {
        return this; //nothing to curry with - return function
    }
    var __method = this;
    var args = toArray(arguments);
    return function() {
        return __method.apply(this, args.concat([].slice.apply(null, arguments)));
    }
}

Eu encontrei funções que se assemelham functools.partial de python mais útil em JavaScript:

function partial(fn) {
  return partialWithScope.apply(this,
    Array.prototype.concat.apply([fn, this],
      Array.prototype.slice.call(arguments, 1)));
}

function partialWithScope(fn, scope) {
  var args = Array.prototype.slice.call(arguments, 2);
  return function() {
    return fn.apply(scope, Array.prototype.concat.apply(args, arguments));
  };
}

Por que você iria querer usá-lo? Uma situação comum onde você quiser usar isso é quando você quer this ligam em uma função para um valor:

var callback = partialWithScope(Object.function, obj);

Agora, quando retorno de chamada é chamado, pontos this para obj. Isso é útil em situações de eventos ou para poupar algum espaço, porque ele geralmente torna o código mais curto.

Currying é semelhante à parcial com a diferença de que a função dos Currying retorna apenas aceita um argumento (tanto quanto eu entendo isso).

Concordando com Hank Gay - É extremamente útil em certas verdadeiras linguagens de programação funcional - porque é uma parte necessária. Por exemplo, em Haskell você simplesmente não pode ter múltiplos parâmetros para uma função - você não pode fazer isso em programação funcional pura. Você toma um parâmetro de cada vez e construir a sua função. Em JavaScript é simplesmente desnecessário, apesar exemplos inventados como "conversor". Aqui está o mesmo código conversor, sem a necessidade de currying:

var converter = function(ratio, symbol, input) {
    return (input*ratio).toFixed(2) + " " + symbol;
}

var kilosToPoundsRatio = 2.2;
var litersToUKPintsRatio = 1.75;
var litersToUSPintsRatio = 1.98;
var milesToKilometersRatio = 1.62;

converter(kilosToPoundsRatio, "lbs", 4); //8.80 lbs
converter(litersToUKPintsRatio, "imperial pints", 2.4); //4.20 imperial pints
converter(litersToUSPintsRatio, "US pints", 2.4); //4.75 US pints
converter(milesToKilometersRatio, "km", 34); //55.08 km

Eu mal deseja Douglas Crockford, em "JavaScript: The Good Parts", tinha dado alguma menção da história e utilização efectiva do currying ao invés de seu discurso improvisado. Durante muito tempo depois de ler isso, eu estava confundia, até que eu estava estudando programação funcional e percebeu que de onde veio.

Depois de mais algum pensamento, eu posição há um caso de uso válido para currying em JavaScript: se você está tentando escrever usando técnicas de programação funcional pura usando JavaScript. Parece ser um caso de uso raro embora.

Aqui está um exemplo.

Estou instrumentar um monte de campos com JQuery para que eu possa ver o que os usuários estão fazendo. Os olhares código como este:

$('#foo').focus(trackActivity);
$('#foo').blur(trackActivity);
$('#bar').focus(trackActivity);
$('#bar').blur(trackActivity);

(para usuários não-JQuery, eu estou dizendo que a qualquer momento um par de campos de obter ou perder o foco, eu quero o trackActivity () função a ser chamada. Eu também poderia usar uma função anônima, mas eu teria que duplicá-lo 4 vezes, então eu puxei-o para fora e nomeou-o.)

Agora verifica-se que um desses campos tem de ser tratado de forma diferente. Eu gostaria de ser capaz de passar um parâmetro em uma dessas chamadas a serem repassados ??para nossa infra-estrutura de monitoramento. Com currying, eu posso.

Não é nenhuma mágica ou qualquer coisa ... apenas uma abreviação agradável para funções anônimas.

partial(alert, "FOO!") é equivalente a function(){alert("FOO!");}

partial(Math.max, 0) corresponde a function(x){return Math.max(0, x);}

As chamadas para parcial ( MochiKit terminologia. Eu acho que algumas outras bibliotecas dar funções de um método .curry que faz a mesma coisa) olhar um pouco mais agradável e menos barulhento do que as funções anônimas.

Como para as bibliotecas de usá-lo, há sempre Funcional .

Quando é útil em JS? Provavelmente os mesmos vezes é útil em outras línguas modernas, mas a única vez que eu posso me ver usá-lo é em conjunto com a aplicação parcial.

Eu diria que, provavelmente, toda a biblioteca de animação em JS estiver usando currying. Ao invés de ter que passar por cada chamada um conjunto de elementos impactados e uma função, descrevendo como o elemento deve comportar, para uma função de ordem superior que irá garantir todas as coisas o tempo, a sua geralmente mais fácil para o cliente a liberação, como API pública alguns função como "slideUp", "fadeIn", que leva apenas elementos como argumentos, e que são apenas algumas função curry retornar a função de alta ordem com o padrão "função de animação" built-in.

funções

JavaScript é chamado lambda em outra linguagem funcional. Ele pode ser usado para compor uma nova API (mais poderoso ou função complext) para com base na entrada simples de outro desenvolvedor. Curry é apenas uma das técnicas. Você pode usá-lo para criar uma API simplificada para chamar uma API complexa. Se você é o develper que usam a API simplificada (por exemplo, você usar jQuery para fazer a manipulação simples), você não precisa usar curry. Mas se você deseja criar a api simplificado, curry é seu amigo. Você tem que escrever um quadro javascript (como jQuery, mootools) ou biblioteca, então você pode apreciar o seu poder. Eu escrevi uma função de curry reforçada, em http://blog.semanticsworks.com /2011/03/enhanced-curry-method.html. Você não precisa o método de curry para fazer currying, ele apenas ajuda a fazer currying, mas você pode sempre fazê-lo manualmente, escrevendo uma função A () {} para voltar outra função B () {}. Para torná-lo mais interessante, use a função B () para retornar outra função C ().

Eu sei que seu antigo discussão, mas eu vou ter que mostrar como isso está sendo usado em bibliotecas javascript:

Vou usar biblioteca lodash.js para descrever esses conceitos concretamente.

Exemplo:

var fn = function(a,b,c){ 
return a+b+c+(this.greet || ‘'); 
}

Aplicação parcial:

var partialFnA = _.partial(fn, 1,3);

Currying:

var curriedFn = _.curry(fn);

Encadernação:

var boundFn = _.bind(fn,object,1,3 );//object= {greet: ’!'}

uso:

curriedFn(1)(3)(5); // gives 9 
or 
curriedFn(1,3)(5); // gives 9 
or 
curriedFn(1)(_,3)(2); //gives 9


partialFnA(5); //gives 9

boundFn(5); //gives 9!

diferença:

depois currying temos uma nova função sem parâmetros pré vinculados.

após a aplicação parcial temos uma função que está ligada com alguns parâmetros pré-ligado.

na ligação que pode vincular um contexto que será usado para substituir ‘isto’, se não padrão consolidado de qualquer função será âmbito janela.

aconselham: Não há necessidade de reinventar a roda. Parcial aplicação / ligação / curtimenta são muito relacionadas. Você pode ver a diferença acima. Utilize este significado em qualquer lugar e as pessoas vão reconhecer o que você está fazendo, sem problemas na compreensão e você terá que usar menos código.

Concordo que às vezes você gostaria de fazer a bola rolar através da criação de uma função de pseudo que terá sempre o valor do primeiro argumento preenchido. Felizmente, me deparei com uma marca nova biblioteca JavaScript chamada jPaq (h < a href = "http://jpaq.org/" rel = "nofollow"> ttp: //jpaq.org/ ) que fornece essa funcionalidade. A melhor coisa sobre a biblioteca é o fato de que você pode baixar a sua própria construção que contém apenas o código que você vai precisar.

Eu só escreveu um exemplo jPaq que mostra algumas aplicações interessantes da função curry. Confira aqui: Funções Currying Up corda

Só queria acrescentar alguns recursos para Functional.js:

Palestra / conferência explicando algumas aplicações http://www.youtube.com/watch?v=HAcN3JyQoyY

Atualizado biblioteca Functional.js: https://github.com/loop-recur/FunctionalJS Alguns ajudantes agradáveis ??(desculpe de novo aqui, nenhuma reputação: p): / Loop-recorrência / PreludeJS

Estou usando esta biblioteca muito recentemente para reduzir a repetição em um clientes js IRC auxiliares de biblioteca. É uma grande coisa - realmente ajuda-se limpo e código de simplificar.

Além disso, se o desempenho se torna um problema (mas isso lib é bastante leve), é fácil basta reescrever usando uma função nativa.

Você pode usar ligamento nativo para rápida, uma solução de linha

function clampAngle(min, max, angle) {
    var result, delta;
    delta = max - min;
    result = (angle - min) % delta;
    if (result < 0) {
        result += delta;
    }
    return min + result;
};

var clamp0To360 = clampAngle.bind(null, 0, 360);

console.log(clamp0To360(405)) // 45

Outra facada nele, de trabalhar com promessas.

(Disclaimer:.. JS noob, vindo do mundo Python Mesmo lá, currying não é usado tanto assim, mas ele pode vir a calhar na ocasião Então eu plagiou o currying função - veja links)

Em primeiro lugar, eu estou começando com uma chamada ajax. Eu tenho algum processamento específico para fazer em caso de sucesso, mas em caso de falha, eu só quero dar ao usuário o feedback que chamando algo resultou em algum erro . No meu código real, eu exibir o feedback de erro em um painel de inicialização, mas estou apenas usando o log aqui.

Eu modifiquei meu url ao vivo para fazer este falhar.

function ajax_batch(e){
    var url = $(e.target).data("url");

    //induce error
    url = "x" + url;

    var promise_details = $.ajax(
        url,
        {
            headers: { Accept : "application/json" },
            // accepts : "application/json",
            beforeSend: function (request) {
                if (!this.crossDomain) {
                    request.setRequestHeader("X-CSRFToken", csrf_token);
                }
        },
        dataType : "json",
        type : "POST"}
    );
    promise_details.then(notify_batch_success, fail_status_specific_to_batch);
}

Agora, aqui, a fim de informar ao usuário que um lote falhou, eu preciso escrever essa informação no manipulador de erro, porque tudo o que está recebendo é uma resposta do servidor.

Eu ainda só tem a informação disponível em tempo de codificação - no meu caso eu tenho um número de possíveis lotes, mas eu não sei qual deles falhou W.O. analisar a resposta do servidor sobre o URL falhou.

function fail_status_specific_to_batch(d){
    console.log("bad batch run, dude");
    console.log("response.status:" + d.status);
}

Vamos fazer isso. saída do console é:

console:

bad batch run, dude utility.js (line 109) response.status:404

Agora, vamos mudar um pouco as coisas e usar um manipulador de falha genérico reutilizável, mas também aquele que é curry em tempo de execução com o contexto conhecida-at-código em tempo de chamada e o tempo de execução informações disponíveis a partir do evento.

    ... rest is as before...
    var target = $(e.target).text();
    var context = {"user_msg": "bad batch run, dude.  you were calling :" + target};
    var contexted_fail_notification = curry(generic_fail, context); 

    promise_details.then(notify_batch_success, contexted_fail_notification);
}

function generic_fail(context, d){
    console.log(context);
    console.log("response.status:" + d.status);
}

function curry(fn) {
     var slice = Array.prototype.slice,
        stored_args = slice.call(arguments, 1);
     return function () {
        var new_args = slice.call(arguments),
              args = stored_args.concat(new_args);
        return fn.apply(null, args);
     };
}

console:

Object { user_msg="bad batch run, dude. you were calling :Run ACL now"} utility.js (line 117) response.status:404 utility.js (line 118)

De modo mais geral, dado o quão difundido o uso de retorno de chamada está em JS, currying parece ser uma ferramenta bastante útil para ter.

https://javascriptweblog.wordpress.com / 2010/04/05 /-cooking-up curry-mais saborosos-funções / http: //www.drdobbs .com /-fonte aberto / currying-e-parciais-funções-em-javasc / 231001821? pgno = 2

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top