2016-11-03 2 views
0
type aexp = 
    | Const of int 
    | Var of string 
    | Power of string * int 
    | Times of aexp list 
    | Sum of aexp list 

    let rec diff : aexp * string -> aexp 
    = fun (exp, var) -> 
    match exp with 
    |Const a -> Const 0 
    |Var x -> if x = var then Const 1 else Var x 
    |Power (s, i) -> 
     if s = var then Times [Const i; Power (s, i - 1)] else Power (s, i) 
    |Times l -> 
     begin match l with 
      |h::t -> Sum ((Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var))))   
     end 
    |Sum l -> 
     begin match l with 
      |h::t -> Sum (diff(h, var) :: diff(t, var)) 
     end 

Ce code devrait fonctionner comme suit:Je suis en difficulté de faire une fonction différenciante en OCaml (pas question de syntaxe)

diff (Times[Const 2; Var "x"], "x") 

alors la sortie doit être

Times[Const 2; Const 1] 

parce que si nous différencions 2x, le résultat est 2

mais l'erreur se produit et il est dit:

File "", line 18, characters 20-25: 
Error: This variant expression is expected to have type 'a list 
     The constructor Times does not belong to type list 

Pourquoi cette erreur se produit-elle? Je pense qu'il y a des points qui ne sont pas corrects, mais je ne trouve aucune erreur logique.

Répondre

1

Regardons à cette expression:

h :: Times (diff (Times t, var)) 

pour plus de simplicité, nous allons substituer diff (Times t, var), avec le dtdv, de sorte que nous avons

h :: Times dtdv 

Le :: constructeur infix exige qu'une expression à la gauche de il doit avoir le type 'a, tandis qu'une expression à droite doit avoir une valeur de type 'a list. Une expression à droite est Times dtdv et le constructeur Times crée des valeurs de type aexp, et non des valeurs de liste de types. Btw, vous avez également deux autres erreurs et deux avertissements supplémentaires. Ces erreurs sont de même nature, à savoir que vous essayez d'appliquer une valeur de type aexp dans un endroit où une liste est nécessaire, à savoir ici:

Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var)) 

Simplifions encore

Times (dhv::t) @ rest 

L'opérateur @ attend des listes sur les deux côtés, et Times something, comme nous l'avons déjà discuté, ne sont pas une liste.

Il semble qu'il vous soit difficile de passer à travers la grande quantité de règles de parenthèses et de précédence. Je déteste la parenthèse. Donc, j'essaie toujours d'utiliser let ... in avec parcimonie, par exemple, nous allons réécrire l'expression suivante:

Sum ((Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var)))) 

Avec plus bavard, mais la version understanble:

let h' = diff (h,var) in 
let t' = diff (Times t,var) in 
let lhs = Times (h'::t) in 
let rhs = h :: Times t' in 
Sum ([email protected]) 

Maintenant, il est beaucoup plus facile à lire, et vous peut s'attaquer à tous les problèmes un par un.

Aussi, je suggère de ne pas essayer de tout résoudre dans une grande fonction de graisse, mais plutôt de séparer les choses en fonctions plus petites qui sont plus faciles à manipuler, cela vous permettra également de résoudre un problème avec une allumette, par exemple, La fonction suivante a une structure qui est beaucoup plus facile à comprendre:

let rec diff : aexp * string -> aexp = fun (exp, var) -> 
    match exp with 
    |Const a -> Const 0 
    |Var x -> if x = var then Const 1 else Var x 
    |Power (s, i) -> diff_power s i 
    |Times l -> diff_times l 
    |Sum l -> diff_sum l 
and diff_power s i = 
    if s = var then Times [Const i; Power (s, i - 1)] else Power (s, i) 
and diff_times l = match l with 
    |h::t -> Sum ((Times (diff (h, var) :: t)) @ (h :: Times (diff (Times t, var)))) 
and diff_sum l = match l with 
    |h::t -> Sum (diff(h, var) :: diff(t, var)) 
+0

Merci de me répondre. Je me demande encore si j'ai déjà déclaré que Times -> aexp list et je pensais que cela signifiait que le constructeur Times faisait une liste de type aexp. Comment puis-je résoudre ce problème? –

+0

@ 송재민: 'diff (Times t, var)' renvoie ou devrait retourner une somme de produits. Qui est une structure 'aexp'' Sum' avec la liste des addens à l'intérieur. Il semble non sensé d'appliquer le constructeur 'Times' à la structure' Sum'. Le résultat correct devrait être quelque chose comme 'diff (Times [u, v, w], x) = Somme [Times [u ', v, w], Times [u, Somme [Times [v', w], Times [ v, Sum [Times [w ']]]]]] '. Idéalement, les sommes et les produits à un seul élément sont déballés ... – LutzL

2

Quelques notes mathématiques:

  • Le dérivé d'une variable non x par une x variable est égal à zéro, pas la variable d'origine . Le même pour une puissance d'une variable pas x, c'est aussi une constante par rapport à x. Pourquoi les seules puissances de variables, (a+b)^i, ne sont pas possibles. Le cas plus général est aussi facile que le cas particulier.

Pour le dérivé du produit tenir compte de trois facteurs et comprennent que la première étape récursive divise u et v*w

(u*v*w)' = u'*v*w + u*(v'*w+v*w') 

Dans une notation préfixée ce qui peut être écrit comme

diff(*[u,v,w])=+[*[u',v,w],*[u,+[*[v',w],*[v,w']]]] 

qui devrait se traduire par quelque chose comme

|h::t -> Sum ((Times (diff (h, var) :: t)) @ (Times (h :: (diff (Times t, var))))) 

sous forme de listes à deux éléments, cela pourrait-il également écrit que

|h::t -> Sum (Times (diff (h, var) :: t) , Times (h ,diff (Times t, var)))