2016-06-12 1 views
3

Dans Haskell, vous pouvez appliquer fmap à deux fonctions, ce qui correspond essentiellement à la composition de la fonction. Vous pouvez même composer fmap pour activer la fonction de composition des fonctions avec une plus grande arité (fmap . fmap).Comment implémenter un foncteur pour que la carte puisse être appliquée à deux fonctions?

Cela fonctionne parce que les fonctions sont des foncteurs.

Comment un tel foncteur (ou la méthode appropriée map) serait-il implémenté en Javascript?

C'est ce que je l'ai essayé jusqu'à présent:

funcProto = { 
    map(f) { return y => f(this.x(y)) } 
}; 

function func(x) { 
    return Object.assign(Object.create(funcProto), {x: x}); 
} 

const comp = f => g => x => f(g(x)); 
const map = f => ftor => ftor.map(f); 
const sub = y => x => x - y; 
const sqr = x => x * x; 
const inc = x => x + 1; 

Cela fonctionne pour la composition de la fonction normale:

func(sqr).map(inc)(2); // 5 

Cependant, il ne fonctionne pas pour une version composée de map:

const map2 = comp(map)(map); 
map2(sub)(sub)(10)(5)(4); // Error 

Je pense que je m'adapte trop à la façon traditionnelle dont les foncteurs sont im plemented en Javascript. Les fonctions en tant que foncteurs se comportent différemment de la liste ou peut-être.

+0

« * la foncteurs façon traditionnelle sont mises en œuvre en Javascript * » - il n'y a rien. – Bergi

Répondre

2

Dans Haskell, tout est une fonction. Dans votre javascript, certaines de vos fonctions sont représentées comme func s avec une méthode .x(), et certaines sont natives Function s. Cela ne peut pas fonctionner.

Voici trois approches:

const sub = y => x => x - y; 
const sqr = x => x * x; 
const inc = x => x + 1; 
const comp = f => g => x => f(g(x)); 
  • fonctions simples, aucune méthode.

    const fmap = comp; // for functions only 
    console.log(fmap(inc)(sqr)(1)) // 5 
    const fmap2 = comp(fmap)(fmap); 
    console.log(fmap2(sub)(sub)(10)(5)(4)); // 9 
    
  • extension Function natif s, en utilisant fmap comme méthode:

    Function.prototype.fmap = function(f) { return comp(this)(f); }; 
    console.log(sqr.fmap(inc)(1)); // 5 
    const fmap2 = comp.fmap(comp) // not exactly what you want, works just like above 
    Function.prototype.fmap2 = function(f) { return this.fmap(g => g.fmap(f)); } // better 
    console.log(sub.fmap2(sub)(10)(5)(4)); // 9 
    
  • la construction de votre propre type de fonction (également ES6):

    function Func(f) { 
        if (!new.target) return new Func(f); 
        this.call = f; 
    } 
    // Ahem. 
    const sub = Func(y => Func(x => x - y)); 
    const sqr = Func(x => x * x); 
    const inc = Func(x => x + 1); 
    const comp = Func(f => Func(g => Func(x => f.call(g.call(x))))); 
    // Now let's start 
    const fmap = Func(f => Func(x => x.fmap(f))); // a typeclass! 
    Func.prototype.fmap = function(f) { return comp(this)(f); }; // an instance of the class! 
    console.log(fmap.call(inc).call(sqr).call(1)); // 5 
    const fmap2 = comp.call(fmap).call(fmap); 
    console.log(fmap2.call(sub).call(sub).call(10).call(5).call(4)); // 9 
    
+0

'const fmap = comp;' est très humoristique, réponse à une question. Sérieusement, 'fmap' et' (.) 'Ont des types différents dans Haskell, donc je me suis demandé pourquoi ils sont équivalents (à condition que fmap soit appliqué à deux fonctions). Et vous dites simplement 'fmap === comp', y faire face. OK alors, il n'y a pas de différence pratique entre 'fmap' et' comp' dans ce contexte et il est probablement peu logique de construire une version 'comp' pour les méthodes en Javascript. J'ai posé cette question à l'origine pour obtenir une meilleure compréhension de 'fmap' et des foncteurs et du fait que les fonctions sont des foncteurs. – ftor

+1

Puisque 'fmap' est une méthode de la classe de type' Functor', elle est définie pour différentes instances de 'Functor' (telles que des listes, par exemple), dont les fonctions ne font qu'un. C'est pourquoi 'fmap' a un type différent (plus général) que' .'. Pour les fonctions, 'fmap' coïncide en effet avec' .'. https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-638 (Désolé, j'étais confus dans mon commentaire précédent, qui est déjà supprimé. – FPstudent

0

Pardonne-moi si je me trompe, mais vous semblez être confus au sujet de Functor s à Haskell. La classe de type Functor dans Haskell représente les types de données sur lesquels la "carte" (fmap pour être plus précis) est défini:

https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor.html

Par exemple, les listes ([] dans Haskell) sont une instance de Functor, comme:

fmap (\x->x+1) [1,2,3] -- returns [2,3,4] 

Comme indiqué dans la documentation ci-dessus, il est vrai que fmap (f . g) devrait être équivalente à fmap f . fmap g (rappelons que . dans Haskell signifie composition de fonction, qui est, (f.g) x est égal à f(g(x))).Par exemple, laissez

f x = x + 1 

et:

g y = y * 2 

Puis

fmap (f.g) [1,2,3] -- equivalent to [(f.g) 1, (f.g) 2, (f.g) 3] 

et

(fmap f . fmap g) [1,2,3] -- equivalent to (fmap f (fmap g [1,2,3])) 

sont équivalentes et les deux reviennent [3,5,7].

Array s en JavaScript sont déjà un Functor dans ce sens car ils ont map.

const f = x => x + 1; 
    const g = y => y * 2; 
    const comp = f => g => x => f(g(x)); 
    const fmap_array = f => a => a.map(f); 

    fmap_array (comp(f)(g)) ([1,2,3]); // [3,5,7] 
    (comp (fmap_array(f)) (fmap_array(g))) ([1,2,3]); // [3,5,7] 

Ou, vous pouvez le faire si vous le souhaitez:

Array.prototype.fmap = function(f) { return this.map(f); } 
    [1,2,3].fmap(f); // [2,3,4] 
    [1,2,3].fmap(g); // [2,4,6] 
    [1,2,3].fmap(comp(f)(g)); // [3,5,7] 
    [1,2,3].fmap(g).fmap(f); // [3,5,7] 

post-scriptum

Maintenant, je vois ce que vous vouliez dire dans votre question - fonctions (-> dans Haskell) sont également une instance de Functor, en effet définie comme la composition de la fonction fmap f g = (f . g):

https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor.html#control.i:ic:Functor:Functor:28

https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-638

Pour quelque chose similaire en JavaScript,

const fmap_func = f => g => comp(f)(g); // or "const fmap_func = comp;"! 
    fmap_func(f)(g)(42); // 85 

ou encore si vous aimez:

Function.prototype.fmap = function(f) { return comp(f)(this); }; 
    g.fmap(f)(42); // 85 
+1

Lorsque vous combinez deux fonctions avec 'fmap' dans Haskell vous obtenez le même résultat qu'avec' (.) '([Voir cette question] (http://stackoverflow.com/questions/27883414/difference-between-function- composition-opérateur-et-fmap)). Et si vous le composez ('fmap. Fmap') il se comporte comme' (.). (.) '([Voir cette réponse] (http://stackoverflow.com/a/5822395)). Pour mieux comprendre le pourquoi j'ai essayé d'implémenter un tel 'fmap' dans Javascript. Mais il s'est avéré que cela n'a aucun sens, parce que 'fmap' (combiné avec deux fonctions) et' comp' sont pratiquement les mêmes en Javascript. – ftor

+0

Je l'ai maintenant - J'ai ajouté un P.S. – FPstudent