The amazing part is that it actually works.
A while back, I saw a quora post showing how automatic differentiation can be achieved in just 20 lines of Haskell. And not just the first derivative, but all of them. Naturally I implemented it on my machine and filled out the Floating implementation.
More recently, I've been playing with LLVM bindings in Haskell and while llvm-hs seems to be the standard, I couldn't stand the boilerplate of it. Now I've been playing with llvm-pretty which I've been really enjoying and, along with parameterizing my types for the specific bit widths, I've been implementing the Num traits for them.
With both of these projects lying around, I just had to put them together.
(\x -> (x^2 + 3*x)/8) (var (4 :: LFloat F32))
After putting that into GHCI, I got this:
define float @f0() {
entry:
%r0 = fmul float 4, 4
%r1 = fmul float 3, 4
%r2 = fadd float %r0, %r1
%r3 = fmul float 8, 8
%r4 = fdiv float 1, %r3
%r5 = fsub float 0, %r4
%r6 = fmul float 0, %r5
%r7 = fmul float %r2, %r6
%r8 = fdiv float 1, 8
%r9 = fmul float 4, 1
%r10 = fmul float 4, 1
%r11 = fadd float %r9, %r10
%r12 = fmul float 3, 1
%r13 = fmul float 4, 0
%r14 = fadd float %r12, %r13
%r15 = fadd float %r11, %r14
%r16 = fmul float %r8, %r15
%r17 = fadd float %r7, %r16
ret float %r17
}
It's quite a bit longer than it needs to be and I haven't provided the argument as an LLVM parameter, but it is valid LLVM IR for the derivative of that function at x = 4.
OK, ya I could probably do most of this in any language with operator overloading, but combined with encoding the LLVM type in the haskell type and it was just so much fun. The next step is to make it output an LLVM function that returns a pair of the value and derivative of a given function at any point. Oh, and maybe run it through the LLVM optimiser so I don't have as many multiples by zero.