4

J'essaie de traduire traverse/sequenceA en Javascript. Maintenant, le comportement suivant de la mise en œuvre Haskell me donne du mal:Le passage de type explicite n'est-il pas équivalent à l'inférence de type (en termes d'expressivité)?

traverse (\x -> x) Nothing -- yields Nothing 
sequenceA Nothing -- yields Nothing 
traverse (\x -> x) (Just [7]) -- yields [Just 7] 
sequenceA (Just [7]) -- yields [Just 7] 

En tant que débutant Haskell Je me demande pourquoi la première expression fonctionne à tous:

instance Traversable Maybe where 
    traverse _ Nothing = pure Nothing 
    traverse f (Just x) = Just <$> f x 

pure Nothing ne devraient pas travailler dans ce cas, étant donné que il n'y a pas de contexte applicatif minimal dans lequel la valeur pourrait être mise. Il semble que le compilateur vérifie paresseusement le type de cette expression et que le mappage de la fonction id sur Nothing est un noop, il "ignore" simplement l'erreur de type, donc parler.

Voici ma traduction Javascript:

(S'il vous plaît noter que depuis le système prototype de Javascirpt est insuffisant pour deux classes de type et il n'y a pas de type vérification stricte de toute façon, je travaille avec le codage de l'Eglise et passe des contraintes de type à fonctions explicitement.)

// minimal type system realized with `Symbol`s 

const $tag = Symbol.for("ftor/tag"); 
const $Option = Symbol.for("ftor/Option"); 

const Option = {}; 

// value constructors (Church encoded) 

const Some = x => { 
    const Some = r => { 
    const Some = f => f(x); 
    return Some[$tag] = "Some", Some[$Option] = true, Some; 
    }; 

    return Some[$tag] = "Some", Some[$Option] = true, Some; 
}; 

const None = r => { 
    const None = f => r; 
    return None[$tag] = "None", None[$Option] = true, None; 
}; 

None[$tag] = "None"; 
None[$Option] = true; 

// Traversable 

// of/map are explicit arguments of traverse to imitate type inference 
// tx[$Option] is just duck typing to enforce the Option type 
// of == pure in Javascript 

Option.traverse = (of, map) => ft => tx => 
tx[$Option] && tx(of(None)) (x => map(Some) (ft(x))); 

// (partial) Array instance of Applicative 

const map = f => xs => xs.map(f); 
const of = x => [x]; 

// helpers 

const I = x => x; 

// applying 

Option.traverse(of, map) (I) (None) // ~ [None] 
Option.traverse(of, map) (I) (Some([7])) // ~ [Some(7)] 

de toute évidence, cette traduction diffère de la mise en œuvre Haskell, parce que je reçois un [None] où je devrais obtenir un None. Honnêtement, ce comportement correspond précisément à mon intuition, mais je suppose que l'intuition n'est pas très utile dans la programmation fonctionnelle. Maintenant, ma question est

  • ai-je simplement fait une erreur de débutant?
  • ou est le type explicite passant pas équivalent à l'inférence de type (en termes d'expressivité)?
+0

L'erreur recrue c'est! – ftor

Répondre

4

GHCi n'oublie aucune erreur de type. Il applique par défaut un Applicative non contraint à IO, mais vous obtenez uniquement ce comportement dans une invite GHCi (et non un fichier source .hs). Vous pouvez vérifier

> :t pure Nothing 
pure Nothing :: Applicative f => f (Maybe b) 

mais encore

> pure Nothing 
Nothing 

Votre implémentation javascript est bien; vous avez passé dans une instance Applicative pour les tableaux et obtenu ce qui est attendu.

+0

Je ris maintenant si je n'avais pas mis autant de travail dans cette question. Je ne sais toujours rien sur Haskell. Merci! – ftor

+0

Donc vous dites que l'instance Traversable avec ceci ne fonctionnera pas? – Bergi

+0

@Bergi non, nous avons juste (heureusement?!?) Aucun type par défaut en Javascript – ftor