anchor.diff:    | WindowAggregation.Mean(fld) -> [ fld, nums fld |> Seq.average |> Number ]
     | WindowAggregation.Min(fld) -> [ fld, nums fld |> Seq.min |> Number ]
     | WindowAggregation.Max(fld) -> [ fld, nums fld |> Seq.max |> Number ]
  +  | WindowAggregation.Sum(fld) -> [ fld, nums fld |> Seq.sum |> Number ]
     | WindowAggregation.FirstKey -> [ "first " + kname, kvalues.[0] ]
     | WindowAggregation.LastKey -> [ "last " + kname, kvalues.[kvalues.Length-1] ]
     | WindowAggregation.MiddleKey -> [ "middle " + kname, kvalues.[(kvalues.Length-1)/2] ]
  +
  +let getExpandAggregationFunction kname agg = 
  +  let ret fld f = fun row -> fld, pickField fld row |> asDecimal |> f |> Number
  +  match agg with
  +  | WindowAggregation.Mean(fld) -> 
  +      let mutable sum = 0M
  +      let mutable count = 0M
  +      ret fld (fun v -> sum <- sum + v; count <- count + v; sum / count)
  +  | WindowAggregation.Min(fld) -> 
  +      let mutable min = Decimal.MaxValue
  +      ret fld (fun v -> (if v < min then min <- v); min)
  +  | WindowAggregation.Max(fld) ->
  +      let mutable max = Decimal.MinValue
  +      ret fld (fun v -> (if v > max then max <- v); max)
  +  | WindowAggregation.Sum(fld) -> 
  +      let mutable sum = 0M
  +      ret fld (fun v -> sum <- sum + v; sum)
  +  | WindowAggregation.FirstKey -> 
  +      let mutable first = None
  +      fun row -> (if first.IsNone then first <- Some (pickField kname row)); "first " + kname, first.Value
  +  | WindowAggregation.LastKey -> 
  +      fun row -> "last " + kname, pickField kname row
  +  | WindowAggregation.MiddleKey -> 
  +      let keys = ResizeArray<_>()
  +      fun row -> keys.Add(pickField kname row); "middle " + kname, keys.[keys.Count/2]
   
   let compareFields o1 o2 (fld, order) = 
     let reverse = if order = Descending then -1 else 1
  
positive.code:         aggs
          |> List.collect (applyWinAggregation fld win)
          |> Array.ofSeq )
    | GroupBy(flds, aggs) ->
        objs 
        |> Seq.groupBy (fun j -> List.map (fun f -> pickField f j) flds)
  
negative.code:         GroupBy(keys, aggs)
      | "windowby", key::size::ops ->
          let key = trimIdent (key.Substring(3))
          let aggs = ops |> List.map (parseOp winNullaryOps winUnaryOps)
          WindowBy(key, int size, aggs)
      | "expandby", key::ops ->
          let key = trimIdent (key.Substring(3))
          let aggs = ops |> List.map (parseOp winNullaryOps winUnaryOps)
          ExpandBy(key, aggs)
      | "take", [n] -> Paging [Take (int n)]
      | "skip", [n] -> Paging [Skip (int n)]
      | _ -> failwith "Unsupported transformation"
  