4

我遇到了以下 F# 示例,发现它很有趣。

http://www.codeproject.com/KB/net-languages/SymbolicCalcInFS.aspx

Clojure 是否有语言/库工具可以轻松地做这样的事情?可以对公式强制使用波兰表示法,如果这会使事情变得更容易。

谢谢,如果有问题请告诉我。

4

6 回答 6

6

Lisp 在符号计算方面有着悠久的历史。请参阅Peter Norvig的 AI 案例研究书。Lisp 提供了很多很棒的语言特性来抽象符号上的常用操作。有时您可以编写非常简洁的代码(比 F# 更简洁/简短)。

像 F# 这样的静态语言具有强大的类型系统和方便的数据类型模式匹配。编译器可以发现类型系统捕获的错误,例如没有考虑一种特殊情况。考虑数据的类型也可以减少运行时错误的机会。F# 中的类型推断也使得 F# 代码非常简洁。

于 2010-10-04T04:20:16.820 回答
6

我对 Clojure 了解不多,但至少这里有一些指针。

使 F# 代码良好的关键特性是代数数据类型的模式匹配。例如,代数数据类型是类型的声明(用于表示数学表达式),模式匹配是用于在实现简化或微分时检查各种已知情况的构造。Expressionmatch

我不认为 Clojure 有任何对模式匹配的内置支持,但它可以作为一个库来实现。一个看起来很有趣的库是模式匹配模块(在 Clojars 中)。这是一个使用它来实现代数求值器的示例(与 F# 文章非常接近)。

F# 文章中出现的另一件事是活动模式(它允许您声明和重用模式)。我不认为有一个 Clojure 库可以做到这一点,但考虑到语言的灵活性,应该也可以实现它们(但是,在 F# 文章中它们并不是真正必要的)

于 2010-10-04T00:53:07.673 回答
4

符号微分是 lisp 的首批应用之一!

我写了一篇关于一个简单的符号微分器的博文。它只处理 + 和 *,但它很容易扩展。

这是我在伦敦的一次会议上向初学者介绍 clojure 的系列文章的一部分,以展示 clojure 操作自己的代码是多么容易。

当然可爱的是做了微分之后就可以编译代码了!因此,您可以生成用户输入的差异化版本,或生成函数及其派生的宏等。

原版在这里,并且很好地突出了语法:

http://www.learningclojure.com/2010/02/clojure-dojo-4-symbolic-differentiation.html

但是我在这里发布了代码,所以你可以看看:

;; The simplest possible symbolic differentiator

;; Functions to create and unpack additions like (+ 1 2)
(defn make-add [ a b ] (list '+ a b))
(defn addition? [x] (and (=(count x) 3) (= (first x) '+)))
(defn add1   [x] (second x))
(defn add2   [x] (second (rest x)))


;; Similar for multiplications (* 1 2)
(defn make-mul [ a b ] (list '* a b))
(defn multiplication? [x] (and (=(count x) 3) (= (first x) '*)))
(defn mul1   [x] (second x))
(defn mul2   [x] (second (rest x)))


;; Differentiation. 
(defn deriv [exp var]
  (cond (number? exp) 0                                                              ;; d/dx c -> 0
        (symbol? exp) (if (= exp var) 1 0)                                           ;; d/dx x -> 1, d/dx y -> 0

        (addition? exp) (make-add (deriv (add1 exp) var) (deriv (add2 exp) var))     ;; d/dx a+b -> d/dx a + d/dx b
        (multiplication? exp) (make-add (make-mul (deriv (mul1 exp) var) (mul2 exp)) ;; d/dx a*b -> d/dx a * b + a * d/dx b
                                        (make-mul (mul1 exp) (deriv (mul2 exp) var)))
        :else :error))


;;an example of use: create the function x -> x^3 + 2x^2 + 1 and its derivative 
(def poly '(+ (+ (* x (* x x)) (* 2 (* x x))) 1))

(defn poly->fnform [poly] (list 'fn '[x] poly))

(def polyfn  (eval (poly->fnform poly)))
(def dpolyfn (eval (poly->fnform (deriv poly 'x))))



;;tests

(use 'clojure.test)

(deftest deriv-test
  (testing "binary operators"
    (is (= (let [m '(* a b)] [(multiplication? m) (make-mul (mul1 m) (mul2 m))]) [true  '(* a b)]))
    (is (= (let [m '(* a b)] [(addition? m)       (make-add (add1 m) (add2 m))]) [false '(+ a b)])))
  (testing "derivative function"

    (is (= (deriv '0 'x)               '0))
    (is (= (deriv '1 'x)               '0))
    (is (= (deriv 'x 'x)               '1))
    (is (= (deriv 'y 'x)               '0))
    (is (= (deriv '(+ x x) 'x)         '(+ 1 1)))
    (is (= (deriv '(* x x) 'x)         '(+ (* 1 x) (* x 1))))
    (is (= (deriv '(* x x) 'y)         '(+ (* 0 x) (* x 0))))
    (is (= (deriv '(* x (* x x)) 'x)   '(+ (* 1 (* x x)) (* x (+ (* 1 x) (* x 1)))))))
  (testing "function creation: d/dx (x^3 + 2x^2 + 1) = 3x^2 + 4x "
    (let [poly '(+ (+ (* x (* x x)) (* 2 (* x x))) 1)]
      (is (= ((eval (poly->fnform poly)) 3) 46))
      (is (= ((eval (poly->fnform (deriv poly 'x))) 3)))))) 
于 2010-10-04T20:46:12.070 回答
2

我没试过,但Clojuratica看起来很有趣。

于 2010-10-04T00:49:59.410 回答
1

好吧,现在 Clojure 提供了强大的模式匹配库:

  1. 匹配:https ://github.com/dcolthorp/matchure
  2. 比赛:https ://github.com/swannodette/match
于 2011-08-30T15:58:32.963 回答
0

是的,像您描述的系统现在存在于 Clojure 上!它是 Gerry Sussman 的伴侣系统,他的 -and Wisdom 的 - SICM(经典力学的结构和解释)一书。对于 Clojure,它被命名为sicmutils,并由 Colin Smith 移植。

我已经在别处简要描述了它 - https://stackoverflow.com/a/41646455/4070712 - 但简而言之,是的,它确实做了你 F# 文章提到的四件事,即。

  1. 差异化:
  2. 代数表达式的简化
  3. 格式化
  4. 表达式解析

还有很多很多...

1)微分(支持全偏微分)

> (defn ff [x y] (* (expt x 3)(expt y 5)))
> ((D ff) 'x 'y) ==> (down (* 3 (expt x 2) (expt y 5)) (* 5 (expt x 3) (expt y 4))) 
> ;; i.e. vector of results wrt to both variables

注意。支持两种类型的向量,“向上”和“向下”以适应协变和逆变表达式

2)表达式的简化:哦,是的......

> (def unity (+ (square sin) (square cos)))
> (unity 'x)   ==> 1 ;; yes we can deal with symbols

3) 格式化:表达式可以在 TeX 中呈现,以便显示美观。我不能在这里简单地展示这一点,但目前正在开发 Maple 风格的笔记本/workshhet,使用 Clojure 的“Gorilla”

4)解析:显然。表达式和函数之间的转换是系统的核心部分。

看看https://github.com/littleredcomputer/sicmutils。你甚至不需要 Clojure 来运行它,你可以使用提供的 Java jar 文件。

于 2017-01-14T04:01:55.753 回答