Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Last active October 31, 2015 00:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CMCDragonkai/b97de3dd75a367dbed47 to your computer and use it in GitHub Desktop.
Save CMCDragonkai/b97de3dd75a367dbed47 to your computer and use it in GitHub Desktop.
Haskell: Ternary Comparison Operators (inspired by ternary choice operator http://zenzike.com/posts/2011-08-01-the-conditional-choice-operator)
{-
The comparison operators are non-associative and not composable.
Thus it is illegal to write: 1 < 2 < 3
The input types of < (Int) does not match the output type (Bool).
1 < 2 < 3 can however be written in math notation, because it denotes:
(1 < 2) && (2 < 3) or (1 < 2) ^ (2 < 3)
It is however possible to create a new ternary operator that supports such a
notation!
-}
-- right hand side
-- less
(.<) :: (Ord a) => a -> a -> (a, Bool)
b .< c | b < c = (b, True)
| b >= c = (b, False)
-- greater
(.>) :: (Ord a) => a -> a -> (a, Bool)
b .> c | b > c = (b, True)
| b <= c = (b, False)
-- less or equal
(.<=) :: (Ord a) => a -> a -> (a, Bool)
b .<= c | b <= c = (b, True)
| b > c = (b, False)
-- greater or equal
(.>=) :: (Ord a) => a -> a -> (a, Bool)
b .>= c | b >= c = (b, True)
| b < c = (b, False)
-- left hand side
-- less
(<.) :: (Ord a) => a -> (a, Bool) -> Bool
a <. (b, True) | a < b = True
| a >= b = False
_ <. (_, False) = False
-- greater
(>.) :: (Ord a) => a -> (a, Bool) -> Bool
a >. (b, True) | a > b = True
| a <= b = False
_ >. (_, False) = False
-- less or equal
(<=.) :: (Ord a) => a -> (a, Bool) -> Bool
a <=. (b, True) | a <= b = True
| a > b = False
_ <=. (_, False) = False
-- greater or equal
(>=.) :: (Ord a) => a -> (a, Bool) -> Bool
a >=. (b, True) | a >= b = True
| a < b = False
_ >=. (_, False) = False
infixr 0 .<
infixr 0 .>
infixr 0 .<=
infixr 0 .>=
infixr 0 <.
infixr 0 >.
infixr 0 <=.
infixr 0 >=.
-- 1 <. 2 .< 3 -- True
-- 3 >. 2 .> 1 -- True
-- 1 <. 4 .> 2 -- True
-- 2 >. 1 .< 3 -- True
-- 1 <=. 1 .<= 1 -- True
-- 2 >=. 1 .>= 1 -- True
{-
As these operators are right associative/fixity, this means
1 <. 2 .< 3 == 1 <. (2 .< 3)
-}
{-
However the implementation above is still not composable. It can be made
composable by chaining Maybe a types, but it is no longer a ternary operator.
This would require a Just constructor at the very end, and a special
operator at the beginning that will turn the Maybe a types into a booleans.
-}
(@<) :: (Ord a) => a -> Maybe a -> Maybe a
b @< Just c | b < c = Just b
| b >= c = Nothing
_ @< Nothing = Nothing
(<@) :: (Ord a) => a -> Maybe a -> Bool
a <@ Just b | a < b = True
| a >= b = False
_ <@ Nothing = False
infixr 0 @<
infixr 0 <@
1 <@ 2 @< 3 @< 5 @< 6 @< Just 8 -- True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment