2016-11-03 3 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 

Этот код должен работать следующим образом:я в беде с созданием функции дифференцирующей в OCaml (не о проблеме синтаксиса)

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

, то выход должен быть

Times[Const 2; Const 1] 

, потому что если мы будем различать 2x, результат равен 2

, но возникает ошибка, и в ней говорится:

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 

Зачем возникает эта ошибка? Я думаю, что есть некоторые пятна, которые ошибочны, но я не могу найти никакой логической некорректности.

ответ

1

Давайте посмотрим на это выражение:

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

для простоты давайте подставим diff (Times t, var) с dtdv, так что мы имеем

h :: Times dtdv 

:: инфикс конструктор требует, чтобы выражение слева от его должен иметь тип 'a, а выражение справа должно иметь значение типа 'a list. Выражение справа - Times dtdv, а конструктор Times создает значения типа aexp, а не значения списка типов.

К тому же у вас также есть еще две ошибки и еще два предупреждения. Эти ошибки одного и того же рода, то есть, вы пытаетесь применить значение типа aexp в месте, где требуется список, то есть здесь:

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

Давайте упростим снова

Times (dhv::t) @ rest 

Оператор @ ожидает списки с обеих сторон, а Times something, как мы уже обсуждали, не являются списком.

Похоже, что вам трудно пройти через большое количество круглых скобок и правил приоритета. Я ненавижу круглые скобки. Таким образом, я всегда стараюсь использовать let ... in экономно, например, давайте перепишем следующее выражение:

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

С более подробной, но 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]) 

Теперь гораздо более удобным для чтения, и вы могут решать все проблемы один за другим.

Кроме того, я предлагаю не пытаться решить все в большой толстой функции, а вместо этого разделить вещи на более мелкие функции, которые легче обрабатывать, это также решит вам проблему с совпадением внутри матча, напримерСледующая функция имеет структуру, которая гораздо легче понять:

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

Спасибо за ответ мне. Я все еще удивляюсь, что я уже объявил, что Times -> aexp list , и я думал, что это означает, что конструктор Times делает список типов aexp. Как это исправить ...? –

+0

@ 송재민: 'diff (Times t, var)' возвращает или должен возвращать сумму продуктов. Это структура 'aexp'' Sum' со списком добавлений внутри. Кажется нечувствительным применять конструктор 'Times' к структуре' Sum'. Правильный результат должен быть чем-то вроде 'diff (Times [u, v, w], x) = Sum [Times [u ', v, w], Times [u, Sum [Times [v', w], Times [ v, Sum [Времена [ш ']]]]]] '. В идеале однокомпонентные суммы и продукты распаковываются ... – LutzL

2

Некоторые математические примечания:

  • Производная переменной не x переменным x равна нулю, а не исходная переменная ,

  • То же самое для мощности переменной не x, она также является постоянной относительно x.

  • Почему только полномочия переменных, (a+b)^i невозможен. Более общий случай так же прост, как и особый случай.

Для производной продукта рассмотрит три фактора, и включает в себя, что первый рекурсивный шаг раскалывает u и v*w

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

В префиксной записи это можно записать в виде

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

что должно быть отражено в чем-то вроде

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

В списках двухэлементными, это могло также быть написано как

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