Унарный минус и число с плавающей запятой в OCaml - PullRequest
4 голосов
/ 24 января 2012

Я хотел, чтобы в моей программе был вектор комплексных чисел, поэтому я написал это:

[|pt 0. 0.; pt -4. 1.; pt -7. -2.; pt 4. 5.; pt 1. 1.|]

Здесь pt - это функция типа float -> float -> Complex.t.Но ocaml отказался скомпилировать это высказывание:

Characters 12-14:
  [|pt 0. 0.; pt -4. 1.; pt -7. -2.; pt 4. 5.; pt 1. 1.|];;
              ^^
Error: This expression has type float -> float -> Complex.t
       but an expression was expected of type int

То, что я хотел сделать здесь, это (очевидно) включить комплексное число, действительная часть которого равна -4, а мнимая часть равна 1. Но ocamlрассматривал то, что я собирался считать унарным минусом, как функцию типа int -> int ->int.

Что мне написать, чтобы делать то, что я хотел?

1 Ответ

12 голосов
/ 24 января 2012

Вот как я думаю (после прочтения документов и экспериментов).На самом деле есть четыре совершенно разных оператора:

-    Integer subtraction        int -> int -> int
-.   Floating subtraction       float -> float -> float
~-   Integer unary negation     int -> int
~-.  Floating unary negation    float -> float

Если бы все использовали эти операторы, все было бы понятно, но, к сожалению, это также довольно неуклюжая запись.По моему опыту операторы ~- и ~-. используются редко.Грамматика OCaml указана, чтобы позволить вам использовать операторы вычитания в качестве унарных операторов отрицания, как и во многих других языках.Если вы делаете это, вам часто приходится использовать лишние скобки.Если вы хотите использовать определенные унарные операторы, вам не нужны скобки.

То есть вы можете написать (как в отредактированном ответе пэда):

[|pt 0. 0.; pt ~-.4. 1.; pt ~-.7. ~-.2.; pt 4. 5.; pt 1. 1.|]

Или выможно написать:

[|pt 0. 0.; pt (-.4.) 1.; pt (-.7.) (-.2.); pt 4. 5.; pt 1. 1.|]

Существует также еще один запутывающий фактор, заключающийся в том, что указывается лексер OCaml, позволяющий использовать оператор вычитания integer для унарного отрицания при его использовании сплавающая постоянная .Опять же, это делает запись более похожей на другие языки.Поскольку это по сути бинарный оператор, здесь вам также нужны круглые скобки.

Это означает, что вы можете написать:

[|pt 0. 0.; pt (-4.) 1.; pt (-7.) (-2.); pt 4. 5.; pt 1. 1.|]

Эта запись работает только для отрицательных плавающих констант.Две другие записи работают для любого выражения, которое вы можете захотеть опровергнуть.

# (-) ;;
- : int -> int -> int = <fun>
# (-.) ;;
- : float -> float -> float = <fun>
# (~-) ;;
- : int -> int = <fun>
# (~-.) ;;
- : float -> float = <fun>

# let f x = x +. 2.0;;
val f : float -> float = <fun>

# f ~-.5.;;
- : float = -3.

# f -.5.;;
Characters 0-1:
  f -.5.;;
  ^
Error: This expression has type float -> float
       but an expression was expected of type float
# f (-.5.);;
- : float = -3.

# f -5.;;
  ^
Error: This expression has type float -> float
       but an expression was expected of type int
# f (-5.);;
- : float = -3.
...