This is starting to look promising.  I think what would be really interesting would be to abstract out the validation logic so that it could be presented in a more declarative fashion, something like

    itemPrice *> \item inputPrice ->
        if inputPrice > 0 then return inputPrice
            else fail ("invalid item price for item " ++ show (item,inputPrice))

    itemTotal *> \item _ -> do
        price <- need $ itemPrice item
        qty <- need $ itemQty item
        return $ price * qty

    itemizedVat *> \item _ -> do
        vatExempt <- need $ vatStatus . client . invoice $ item
        if vatExempt then return 0 else do
            total <- need $ itemTotal item
            rate <- need $ vatRate item
            return $ calcVatForValue total rate

    total *> \invoice _ -> do
        itemTotals <- forM (items invoice) $ \item -> (,) <$> need (itemTotal item) <*> need (itemizedVat item)
        let (itemVals,vatVals) = unzip itemTotals
            subTotal = sum itemVals
            vatTotal = sum vatVals
        return $ Total { subTotal, vatTotal, fullTotal = subTotal+vatTotal }

Inspired by the shake build system.  Off the top of my head, so there's no system I know of that implements something like this.  But it might be a nice way to declare complex validation rules, perhaps?  Error handling could be handled by individual rules, so we know if there's a valid itemPrice and itemQty, the itemTotal is valid too.

It might be tricky to implement this exactly as-is, I'm using "itemTotal" as both a tag to specify a rule match and also a field name.  And typing some of the input/output stuff might be non-trivial.  Seems like something that could benefit from a specialized DSL.

John L.

On Thu, Aug 14, 2014 at 5:06 AM, Alberto G. Corona <agocorona@gmail.com> wrote:
Formlets ever had cascade validation:

data Item= Item{ name ::String, quantity, price :: Int}

Item <$>
       <*> inputString `validate` nonEmpty
       <*> inputInt
       <*> inputInt 
 `validate` ( \item -> do
      if theUniverseIsSpanding then do
           if name item == "carrots" && price=="10" then
                       fail "we don´t like 10 cent carrots  in an expanding universe"
           else if.....


2014-08-14 11:41 GMT+02:00 Tom Ellis <tom-lists-haskell-cafe-2013@jaguarpaw.co.uk>:

On Thu, Aug 14, 2014 at 11:28:53AM +0200, Wojtek Narczyński wrote:
> On 14.08.2014 09:19, Tom Ellis wrote:
> >On Wed, Aug 13, 2014 at 05:21:28PM -0700, John Lato wrote:
> >>On Wed, Aug 13, 2014 at 4:21 PM, Tom Ellis
> >>>     data LineItem = LineItem { name :: Maybe String
> >>>                              , quantity :: Maybe Quantity
> >>>                              , price :: Maybe Price }
> >>Rather than this definition, what about something like:
> >>
> >>     data LineItemF f = LineItem
> >>         { name :: f String
> >>         , quantity :: f Quantity
> >>         , price :: f Price }
> >It seems Wojtek already objected to this approach, though perhaps that
> >objection could be overcome
>
> Hmm, perhaps like this
>
> LineItemFi = LineItemFi
>    { name :: StringFi
>    , quantity :: QuantityFi
>    , price :: PriceFi }
>
>
> data LineItemUi f = LineItemUi
>     { name :: StringUi
>     , quantity :: QuantityUi
>     , price :: PriceUi }

You didn't use f there.
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



--
Alberto.

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe