Comparison chain
From HaskellWiki
(Difference between revisions)
(initialized) |
(add another way) |
||
| (One intermediate revision not shown.) | |||
| Line 102: | Line 102: | ||
</haskell> | </haskell> | ||
| + | * You can represent a successful sequence of comparisons with <code>Just a</code> and a failed sequence with <code>Nothing</code>: | ||
| + | <haskell> | ||
| + | module ChainRelation2 where | ||
| + | |||
| + | import Data.Maybe (isJust) | ||
| + | |||
| + | lift :: (a -> b -> Bool) -> Maybe a -> b -> Maybe b | ||
| + | lift f (Just x) y | f x y = Just y | ||
| + | lift _ _ _ = Nothing | ||
| + | |||
| + | (<:) = lift (<) | ||
| + | (<=:) = lift (<=) | ||
| + | (*:) = lift elem | ||
| + | |||
| + | example = isJust (Just 4 <: 5 <=: 6 *: [6,7]) | ||
| + | |||
| + | -- Python equivalent: 4 < 5 <= 6 in [6,7] | ||
| + | </haskell> | ||
| + | |||
| + | [[Category:Mathematics]] | ||
[[Category:FAQ]] | [[Category:FAQ]] | ||
[[Category:Idioms]] | [[Category:Idioms]] | ||
[[Category:Code]] | [[Category:Code]] | ||
Current revision
Contents |
1 Problem
Question:
The compiler doesn't accepta <= x <= b
Answer: The expression cannot be parsed,
because the infix symbol<=
In languages like C
the expression is parsed as (a <= x) <= b which is even worse.
The first part is evaluated to a boolean value,
which is then compared with b.
(For C "boolean" and "integer" are the same type.)
2 Solutions
2.1 simple
- You must be aware, that the mathematical notation
is shorthand for
. Consequently a possible Haskell solution is .a <= x && x <= b - Another fine mathematical notation is
. You can roll your own function
isInRange :: Ord a => a -> a -> a -> Bool isInRange lower upper x = lower <= x && x <= upper
- to capture this notation (), orisInRange a b x
(<?) :: Ord a => a -> (a,a) -> Bool (<?) = flip (uncurry isInRange)
- (). In case of integers you can use thex <? (a,b)function frominRangeclass.Ix
- You can easily write a function, which checks if a list of numbers increases monotonicly.
monotonicIncreasing :: Ord a => [a] -> Bool monotonicIncreasing xs = and (zipWith (<=) xs (tail xs))
- You can use that for the initial problem by .monotonicIncreasing [a,x,b]
2.2 complex
- For more complex checks of whether an element is contained in some ranges, you should have a look at the ranged sets library.
- If you want to program more complex chains with different kinds of comparisons, try the following code.
module ChainRelation where {- * chains of relations (comparison, subsets, logical implications etc.) -} infixr 4 &-, -& type Rel a = (a -> a -> Bool) type Chain a = [(Rel a, a)] endChain :: Chain a endChain = [] -- separate comparison and operand (&-) :: Rel a -> (a, Chain a) -> Chain a rel &- (x,xs) = (rel,x):xs -- separate operand and comparison (-&) :: a -> Chain a -> (a, Chain a) (-&) = (,) -- check if all comparisons are true check :: (a, Chain a) -> Bool check (x,chain) = let (rels,xs) = unzip chain in and (zipWith3 id rels (x:xs) xs) example1 :: Bool example1 = check (1 -& (<) &- 5 -& (==) &- 5 -& (<=) &- 10 -& (endChain :: Chain Integer)) {- * specialised infix operators for comparison -} infixr 4 ==:, /=:, <:, >:, <=:, >=: (==:), (/=:), (<:), (>:), (<=:), (>=:) :: Ord a => a -> (a, Chain a) -> (a, Chain a) (==:) = lift (==) (/=:) = lift (/=) (<:) = lift (<) (>:) = lift (>) (<=:) = lift (<=) (>=:) = lift (>=) lift :: Rel a -> a -> (a, Chain a) -> (a, Chain a) lift f x (y,chain) = (x, (f,y):chain) example2 :: Bool example2 = check (1 <: 5 ==: 5 <=: 10 -& (endChain :: Chain Integer))
- You can represent a successful sequence of comparisons with
Just aand a failed sequence withNothing:
module ChainRelation2 where import Data.Maybe (isJust) lift :: (a -> b -> Bool) -> Maybe a -> b -> Maybe b lift f (Just x) y | f x y = Just y lift _ _ _ = Nothing (<:) = lift (<) (<=:) = lift (<=) (*:) = lift elem example = isJust (Just 4 <: 5 <=: 6 *: [6,7]) -- Python equivalent: 4 < 5 <= 6 in [6,7]
Categories: Mathematics | FAQ | Idioms | Code
