2016-11-12 2 views
2

J'essaie de faire une version typée de React comme un exercice dans Ocaml. Pour le rendre plus fonctionnel, je passe un enregistrement comme argument à rendre.Ocaml inférence de type incorrecte

type ('props,'state) reactInstance = 
    { 
    props: 'props; 
    state: 'state; 
    updater: 'a . ('props,'state) reactInstance -> 'a -> 'state -> unit;} 
and ('props,'state) reactClass = 
    { 
    getInitialState: unit -> 'state; 
    render: ('props,'state) reactInstance -> element;} 

module type ComponentBluePrint = 
    sig 
    type props 
    type state 
    val getInitialState : unit -> state 
    val render : (props,state) reactInstance -> element 
    end 

module type ReactClass = 
    sig 
    type props 
    type state 
    val mkUpdater : 
    props -> 
    ((props,state) reactInstance -> 'e -> state) -> 
     (props,state) reactInstance -> 'e -> unit 
    val reactClass : (props,state) reactClass 
    end 

module CreateComponent(M:ComponentBluePrint) = 
    (struct 
    include M 
    let rec mkUpdater props f i e = 
     let nextState = f i e in 
     let newInstance = 
     { props; state = nextState; updater = (mkUpdater props) } in 
     () 

    let reactClass = 
     { render = M.render; getInitialState = M.getInitialState } 
    end : (ReactClass with type props = M.props and type state = M.state)) 

Une chose que je ne comprends pas pourquoi le compilateur ne peut pas déduire le type de updater = (mkUpdater props) dans let newInstance = { props; state = nextState; updater = (mkUpdater props) }.

Error: Signature mismatch: 
     Values do not match: 
     let mkUpdater : 
    props => 
    (reactInstance props state => '_a => '_b) => 
    reactInstance props state => '_a => unit 
     is not included in 
     let mkUpdater : 
    props => 
    (reactInstance props state => 'e => state) => 
    reactInstance props state => 'e => unit 

Quelle est la différence entre '_a et' e? Cela me ressemble exactement. Comment puis-je faire ce type de vérification?

+0

L'erreur que vous avez indiquée n'est pas la vraie que votre fichier produit. La bonne erreur est "Erreur: Cette expression a type ('a ->' b -> 'c) ->' a -> 'b ->' d mais une expression était attendue du type ('e,' c) reactInstance -> 'f ->' c -> unité Type 'a ->' b -> 'c n'est pas compatible avec type (' e ', c) reactInstance " – Drup

+0

Il y a plusieurs choses qui ressemblent à des erreurs dans le fichier, mais il est difficile de les résoudre sans savoir quelle est la sémantique supposée de vos opérations. La première chose qui me vient à l'esprit, cependant, c'est le '' a. '' Dans le domaine de la mise à jour, êtes-vous sûr de vouloir utiliser un forall ici? Cela ne semble pas très utile. – Drup

Répondre

2

Une variable de type '_a (la lettre réelle n'a pas d'importance, le point crucial est le trait de soulignement) est une variable de type faible. C'est une variable qui ne peut pas être généralisée, c'est-à-dire qu'elle peut être remplacée par un seul type concret. C'est comme une valeur mutable, mais dans le domaine des types.

Un type noté avec une variable de type faible '_a n'est pas inclus dans un type qui est indiqué par une variable de type générique. De plus, il ne peut même pas échapper à l'unité de compilation, et devrait être caché ou concrétisé.

Les variables de type faible sont créées lorsqu'une expression n'est pas une valeur pure (définie syntaxiquement). Habituellement, il s'agit d'une application de fonction ou d'une abstraction. Il est généralement possible de se débarrasser des variables de type faible en effectuant ce que l'on appelle une expansion eta lorsque vous substituez une fonction partiellement appliquée à une application de fonction normale en énumérant tous les arguments de fonction, c'est-à-dire updater = (fun props f i e -> mkUpdater props f i e).

+0

merci pour la bonne explication! – Seneca