Idris2/libs/prelude/Prelude/Basics.idr
observant 1e6e125190
Add pipeline operators (#3284)
* Add pipeline operators

* Fix tests

* Change fixity, add tests

* [ fix ] silence actual fixity

---------

Co-authored-by: itmuckel <18561536+itmuckel@users.noreply.github.com>
Co-authored-by: Guillaume Allais <guillaume.allais@ens-lyon.org>
2024-06-06 10:59:30 +01:00

226 lines
5.1 KiB
Idris

module Prelude.Basics
import Builtin
import Prelude.Ops
%default total
||| `Not x` is an alias for `x -> Void`, indicating that any term of type `x`
||| leads to a contradiction. It can be used in conjunction with `void` or
||| `absurd`.
public export
Not : Type -> Type
Not x = x -> Void
-----------------------
-- UTILITY FUNCTIONS --
-----------------------
||| Manually assign a type to an expression.
||| @ a the type to assign
||| @ x the element to get the type
public export %inline
the : (0 a : Type) -> (1 x : a) -> a
the _ x = x
||| Identity function.
public export %inline
id : (x : a) -> a
id x = x
||| Function that duplicates its input
public export
dup : a -> (a, a)
dup x = (x, x)
||| Constant function. Ignores its second argument.
public export %inline
const : a -> b -> a
const x = \value => x
||| Function composition.
public export %inline %tcinline
(.) : (b -> c) -> (a -> b) -> a -> c
(.) f g = \x => f (g x)
||| Composition of a two-argument function with a single-argument one.
||| `(.:)` is like `(.)` but the second argument and the result are two-argument functions.
||| This operator is also known as "blackbird operator".
public export %inline %tcinline
(.:) : (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.) . (.)
||| `on b u x y` runs the binary function b on the results of applying
||| unary function u to two arguments x and y. From the opposite perspective,
||| it transforms two inputs and combines the outputs.
|||
||| ```idris example
||| ((+) `on` f) x y = f x + f y
||| ```
|||
||| Typical usage:
|||
||| ```idris example
||| sortBy (compare `on` fst).
||| ```
public export %tcinline
on : (b -> b -> c) -> (a -> b) -> a -> a -> c
on f g = \x, y => g x `f` g y
export infixl 0 `on`
||| Takes in the first two arguments in reverse order.
||| @ f the function to flip
public export %tcinline
flip : (f : a -> b -> c) -> b -> a -> c
flip f = \x, y => f y x
||| Function application.
public export %tcinline
apply : (a -> b) -> a -> b
apply f = \a => f a
public export
curry : ((a, b) -> c) -> a -> b -> c
curry f a b = f (a, b)
public export
uncurry : (a -> b -> c) -> (a, b) -> c
uncurry f (a, b) = f a b
||| ($) is compiled specially to shortcut any tricky unification issues, but if
||| it did have a type this is what it would be, and it might be useful to
||| use directly sometimes (e.g. in higher order functions)
public export
($) : forall a, b . ((x : a) -> b x) -> (x : a) -> b x
($) f a = f a
||| Pipeline style function application, useful for chaining
||| functions into a series of transformations, reading top
||| to bottom.
|||
||| ```idris example
||| [[1], [2], [3]] |> join |> map (* 2)
||| ```
public export
(|>) : a -> (a -> b) -> b
a |> f = f a
||| Backwards pipeline style function application, similar to $.
|||
||| ```idris example
||| unpack <| "hello" ++ "world"
||| ```
public export
(<|) : (a -> b) -> a -> b
f <| a = f a
-------------------
-- PROOF HELPERS --
-------------------
||| Equality is a congruence.
public export
cong : (0 f : t -> u) -> (0 p : a = b) -> f a = f b
cong f Refl = Refl
||| Two-holed congruence.
export
-- These are natural in equational reasoning.
cong2 : (0 f : t1 -> t2 -> u) -> (0 p1 : a = b) -> (0 p2 : c = d) -> f a c = f b d
cong2 f Refl Refl = Refl
||| Dependent version of `cong`.
public export
depCong : {0 p : a -> Type} ->
(0 f : (x : a) -> p x) ->
{0 x1, x2 : a} ->
(prf : x1 = x2) ->
f x1 = f x2
depCong f Refl = Refl
||| Dependent version of `cong2`.
public export
depCong2 : {0 p : a -> Type} ->
{0 q : (x : a) -> (y : p x) -> Type} ->
(0 f : (x : a) -> (y : p x) -> q x y) ->
{0 x1, x2 : a} -> (prfX : x1 = x2) ->
{0 y1 : p x1} -> {y2 : p x2} ->
(prfY : y1 = y2) -> f x1 y1 = f x2 y2
depCong2 f Refl Refl = Refl
||| Irrelevant equalities can always be made relevant
export
irrelevantEq : (0 _ : a ~=~ b) -> a ~=~ b
irrelevantEq Refl = Refl
--------------
-- BOOLEANS --
--------------
||| Boolean Data Type.
public export
data Bool = False | True
||| Boolean NOT.
%inline
public export
not : (b : Bool) -> Bool
not True = False
not False = True
||| Boolean AND only evaluates the second argument if the first is `True`.
%inline
public export
(&&) : (b : Bool) -> Lazy Bool -> Bool
(&&) True x = x
(&&) False x = False
||| Boolean OR only evaluates the second argument if the first is `False`.
%inline
public export
(||) : (b : Bool) -> Lazy Bool -> Bool
(||) True x = True
(||) False x = x
||| Non-dependent if-then-else
%inline
public export
ifThenElse : (b : Bool) -> Lazy a -> Lazy a -> a
ifThenElse True l r = l
ifThenElse False l r = r
%inline
public export
intToBool : Int -> Bool
intToBool 0 = False
intToBool x = True
--------------
-- LISTS --
--------------
||| Generic lists.
public export
data List a =
||| Empty list
Nil
| ||| A non-empty list, consisting of a head element and the rest of the list.
(::) a (List a)
%name List xs, ys, zs
||| Snoc lists.
public export
data SnocList a =
||| Empty snoc-list
Lin
| ||| A non-empty snoc-list, consisting of the rest of the snoc-list and the final element.
(:<) (SnocList a) a
%name SnocList sx, sy, sz