{-|
    Module      :  AERN2.Select
    Description :  multivalued select operation
    Copyright   :  (c) Michal Konecny
    License     :  BSD3

    Maintainer  :  mikkonecny@gmail.com
    Stability   :  experimental
    Portability :  portable

    Generic multivalued select operation
-}
module AERN2.Select where

import MixedTypesNumPrelude

import qualified Numeric.CollectErrors as CN

import AERN2.Kleenean

class (IsBool (SelectType k)) => CanSelect k where
  {-| Must be Bool or similar -}
  type SelectType k 
  {-|
    Execute two lazy computations "in parallel" until one of them succeeds. 
  -}
  select :: k -> k -> (SelectType k) {-^ True means that the first computation succeeded. -}

instance CanSelect Kleenean where
  type SelectType Kleenean = CN Bool
  select :: Kleenean -> Kleenean -> SelectType Kleenean
select Kleenean
CertainTrue Kleenean
_ = Bool -> CN Bool
forall v. v -> CN v
cn Bool
True
  select Kleenean
_ Kleenean
CertainTrue = Bool -> CN Bool
forall v. v -> CN v
cn Bool
False
  select Kleenean
CertainFalse Kleenean
CertainFalse =
    NumError -> CN Bool
forall v. NumError -> CN v
CN.noValueNumErrorPotential (NumError -> CN Bool) -> NumError -> CN Bool
forall a b. (a -> b) -> a -> b
$ 
      String -> NumError
CN.NumError String
"select (Kleenean): Both branches failed!"
  select Kleenean
_ Kleenean
_ = 
    NumError -> CN Bool
forall v. NumError -> CN v
CN.noValueNumErrorPotential (NumError -> CN Bool) -> NumError -> CN Bool
forall a b. (a -> b) -> a -> b
$ 
      String -> NumError
CN.NumError String
"select (Kleenean): Insufficient information to determine selection."

instance CanSelect (CN Kleenean) where
  type SelectType (CN Kleenean) = CN Bool
  select :: CN Kleenean -> CN Kleenean -> SelectType (CN Kleenean)
select CN Kleenean
cnk1 CN Kleenean
cnk2 =
    do
    Kleenean
k1 <- CN Kleenean
cnk1
    Kleenean
k2 <- CN Kleenean
cnk2
    Kleenean -> Kleenean -> SelectType Kleenean
forall k. CanSelect k => k -> k -> SelectType k
select Kleenean
k1 Kleenean
k2