Подвижный: многострочное сообщение о фиксации на командной строке?
Хит входят.
$ hg commit -m "Did some work
> Now I'm done"
Одна из вещей - то, что только первые выстраивают в линию шоу в журнале hg:
$ hg log
changeset: 0:d2dc019450a2
tag: tip
user: Aaron Maenpaa <zacherates@gmail.com>
date: Sat Jan 24 07:46:23 2009 -0500
summary: Did some work
..., но если Вы разжигаете "hg представление", Вы видите, что целое сообщение там.
Отредактированный для добавления:
..., но hg-v журнал показывает целое сообщение:
$ hg -v log
changeset: 0:d2dc019450a2
tag: tip
user: Aaron Maenpaa <zacherates@gmail.com>
date: Sat Jan 24 07:46:23 2009 -0500
files: work
description:
Did some work
Now I'm done
Сворачивание последовательностей - это распространенный способ замены циклов аккумулятором.
let Lagrange(pos:_[], v:_[], desiredPos) =
seq {0 .. v.Length-1}
|> Seq.fold (fun retVal i ->
seq {for j in 0 .. pos.Length-1 do if i <> j then yield j}
|> Seq.fold (fun w j -> w * (desiredPos - pos.[j]) / (pos.[i] - pos.[j])) 1.0
|> (fun weight -> weight * v.[i] + retVal)) 0.0
Here's a non-recursive solution. It's a bit funky because the algorithm requires indices, but hopefully it shows how F#'s functions can be composed:
let Lagrange (pos : float[]) (vals : float[]) desiredPos =
let weight pos desiredPos (i,v) =
let w = pos |> Array.mapi (fun j p -> j,p)
|> Array.filter (fun (j,p) -> i <> j)
|> Array.fold (fun acc (j,p) -> acc * (desiredPos - p)/(pos.[i] - p)) 1.
w * v
vals |> Array.mapi (fun i v -> i,v)
|> Array.sumBy (weight pos desiredPos)
The part that makes your functional solution ugly is skipping the i'th element, which means indices. Pull that out into a reusable function so that all the ugly index handling is isolated. I call mine RoundRobin.
let RoundRobin l = seq {
for i in {0..Seq.length l - 1} do
yield (Seq.nth i l, Seq.take i l |> Seq.append <| Seq.skip (i+1) l)
}
It could be a lot uglier if you want to produce an efficient version, though.
I couldn't find product
in the Seq module, so I wrote my own.
let prod (l : seq<float>) = Seq.reduce (*) l
Now producing the code is fairly simple:
let Lagrange pos value desiredPos = Seq.sum (seq {
for (v,(p,rest)) in Seq.zip value (RoundRobin pos) do
yield v * prod (seq { for p' in rest do yield (desiredPos - p') / (p - p') })
})
RoundRobin ensures that pos[i] is not included with the rest of pos in the inner loop. To include the val
array, I zipped it with the round-robinned pos
array.
The lesson here is that indexing is very ugly in a functional style.
Также я обнаружил классный трюк: |> Seq.append <|
дает вам инфиксный синтаксис для добавления последовательностей. Но не так хорошо, как ^
.
Я думаю, что это прекрасно работает как императивный код:
let LagrangeI(pos:_[], v:_[], desiredPos) =
let mutable retVal = 0.0
for i in 0..v.Length-1 do
let mutable weight = 1.0
for j in 0..pos.Length-1 do
// The i-th term has to be skipped
if j <> i then
weight <- weight * (desiredPos - pos.[j]) / (pos.[i] - pos.[j])
retVal <- retVal + weight * v.[i]
retVal
но если вы хотите функциональность, некоторые свертки (вместе с mapi, поскольку вам часто нужно носить с собой индексы) работают хорошо:
let LagrangeF(pos:_[], v:_[], desiredPos) =
v |> Seq.mapi (fun i x -> i, x)
|> Seq.fold (fun retVal (i,vi) ->
let weight =
pos |> Seq.mapi (fun j x -> j<>i, x)
|> Seq.fold (fun weight (ok, posj) ->
if ok then
weight * (desiredPos - posj) / (pos.[i] - posj)
else
weight) 1.0
retVal + weight * vi) 0.0
Я не знаю математики здесь, поэтому я использовал несколько случайных значений для проверки (надеюсь), чтобы убедиться, что я ничего не напортачил:
let pos = [| 1.0; 2.0; 3.0 |]
let v = [|8.0; 4.0; 9.0 |]
printfn "%f" (LagrangeI(pos, v, 2.5)) // 5.375
printfn "%f" (LagrangeF(pos, v, 2.5)) // 5.375
let rec GetWeight desiredPos i j (pos : float[]) weight =
if j = pos.Length then weight
elif i = j then GetWeight desiredPos i (j+1) pos weight
else GetWeight desiredPos i (j+1) pos (weight * (desiredPos - pos.[j])/(pos.[i] - pos.[j]) )
let rec Lagrange (pos : float[]) (vals : float[]) desiredPos result counter =
if counter = pos.Length then result
else Lagrange pos vals desiredPos (result + (GetWeight desiredPos counter 0 pos 1.0)* vals.[counter]) (counter+1)
Лично я считаю, что простые конструкции if / elif / else выглядят здесь намного лучше без таких накладных расходов, как
match i with
|i when i=...
Если вы просто возитесь, то вот версия, похожая на версию Брайана, которая использует каррирование функций и оператор канала кортежа.
let Lagrange(pos:_[], v:_[], desiredPos) =
let foldi f state = Seq.mapi (fun i x -> i, x) >> Seq.fold f state
(0.0, v) ||> foldi (fun retVal (i, posi) ->
(1.0, pos) ||> foldi (fun weight (j, posj) ->
if j <> i then
(desiredPos - posj) / (posi - posj)
else
1.0)
|> (fun weight -> weight * posi + retVal))