-- The 'ignore-exports' option allows us to define our own documentation for == -- and \= while secretly exporting the original Haskell definitions, which are -- the only ones that can be used in defining custom Eq typeclasses. -- | Tons of useful functions that get imported by default. module Basics ( -- * Math Int, Float, (+), (-), (*), (/), (//), (^), toFloat, round, floor, ceiling, truncate, -- * Equality (==), (/=), -- * Comparison -- | These functions only work on @Order@-able types. This includes numbers, -- characters, strings, lists of comparable things, and tuples of comparable -- things. (<), (>), (<=), (>=), max, min, compare, Order, Prelude.Ordering (Prelude.LT, Prelude.GT, Prelude.EQ), -- * Booleans Prelude.Bool (..), not, (&&), (||), xor, -- * Append Strings and Lists (++), -- * Fancier Math modBy, remainderBy, negate, abs, clamp, sqrt, logBase, e, -- * Angles degrees, radians, turns, -- * Trigonometry pi, cos, sin, tan, acos, asin, atan, atan2, -- * Polar Coordinates toPolar, fromPolar, -- * Floating Point Checks isNaN, isInfinite, -- * Function Helpers identity, always, (<|), (|>), (<<), (>>), Never, never, -- * Often-implemented typeclasses Prelude.Eq, Prelude.Ord, Prelude.Num, ) where import qualified Data.Bits (xor) import qualified Data.Int (Int64) import qualified Data.Void (Void, absurd) import Prelude (otherwise) import qualified Prelude -- INFIX OPERATORS infixr 0 <| infixl 0 |> infixr 2 || infixr 3 && infix 4 == infix 4 /= infix 4 < infix 4 > infix 4 <= infix 4 >= infixr 5 ++ infixl 6 + infixl 6 - infixl 7 * infixl 7 / infixl 7 // infixr 8 ^ infixl 9 << infixr 9 >> -- | An @Int@ is a whole number. Valid syntax for integers includes: -- -- > 0 -- > 42 -- > 9000 -- > 0xFF -- 255 in hexadecimal -- > 0x000A -- 10 in hexadecimal -- -- __Note:__ @Int@ math is well-defined in the range @-2^31@ to @2^31 - 1@. -- -- __Historical Note:__ The name @Int@ comes from the term [integer](https://en.wikipedia.org/wiki/Integer). It appears that the @int@ abbreviation was introduced in [ALGOL 68](https://en.wikipedia.org/wiki/ALGOL_60), shortening it from @integer@ in [ALGOL 60](https://en.wikipedia.org/wiki/ALGOL_68). Today, almost all programming languages use this abbreviation. type Int = Data.Int.Int64 -- | A @Float@ is a [floating-point number](https://en.wikipedia.org/wiki/Floating-point_arithmetic). Valid syntax for floats includes: -- -- > 0 -- > 42 -- > 3.14 -- > 0.1234 -- > 6.022e23 -- == (6.022 * 10^23) -- > 6.022e+23 -- == (6.022 * 10^23) -- > 1.602e-19 -- == (1.602 * 10^-19) -- > 1e3 -- == (1 * 10^3) == 1000 -- -- __Historical Note:__ The particular details of floats (e.g. @NaN@) are -- specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) which is -- literally hard-coded into almost all CPUs in the world. That means if you -- think @NaN@ is weird, you must successfully overtake Intel and AMD with a -- chip that is not backwards compatible with any widely-used assembly -- language. type Float = Prelude.Double -- | Add two numbers. The @number@ type variable means this operation can be -- specialized to @Int -> Int -> Int@ or to @Float -> Float -> Float@. So you -- can do things like this: -- -- > 3002 + 4004 == 7006 -- all ints -- > 3.14 + 3.14 == 6.28 -- all floats -- -- You _cannot_ add an @Int@ and a @Float@ directly though. Use functions like -- 'toFloat' or 'round' to convert both values to the same type. So if you -- needed to add a list length to a @Float@ for some reason, you could say one -- of these: -- -- > 3.14 + toFloat (List.length [1,2,3]) == 6.14 -- > round 3.14 + List.length [1,2,3] == 6 -- -- __Note:__ Languages like Java and JavaScript automatically convert @Int@ -- values to @Float@ values when you mix and match. This can make it difficult -- to be sure exactly what type of number you are dealing with. When you try to -- /infer/ these conversions (as Scala does) it can be even more confusing. Elm -- has opted for a design that makes all conversions explicit. (+) :: Prelude.Num number => number -> number -> number (+) = (Prelude.+) -- | Subtract numbers like @4 - 3 == 1@. -- -- See @'(+)'@ for docs on the @number@ type variable. (-) :: Prelude.Num number => number -> number -> number (-) = (Prelude.-) -- | Multiply numbers like @2 * 3 == 6@. -- -- See @'(+)'@ for docs on the @number@ type variable. (*) :: Prelude.Num number => number -> number -> number (*) = (Prelude.*) -- | Floating-point division: -- -- > 3.14 / 2 == 1.57 (/) :: Float -> Float -> Float (/) = (Prelude./) -- | Integer division: -- -- > 3 // 2 == 1 -- -- Notice that the remainder is discarded. (//) :: Int -> Int -> Int (//) = -- Prelude.div truncates towards negative infinity which differs from Elm's -- behaviour. Prelude.quot -- | Exponentiation -- -- > 3^2 == 9 -- > 3^3 == 27 -- -- Breaking from Elm here, in that this is only defined for @Float@ arguments. -- The exponentiation story in Haskell is a little more complex. See the @(^)@, -- @(^^)@, and @(__)@ operations as a starting point. (^) :: Float -> Float -> Float (^) = (Prelude.**) -- * Int to Float / Float to Int -- | Convert an integer into a float. Useful when mixing @Int@ and @Float@ -- values like this: -- -- > halfOf :: Int -> Float -- > halfOf number = -- > toFloat number / 2 toFloat :: Int -> Float toFloat = Prelude.fromIntegral -- | Round a number to the nearest integer. -- -- > round 1.0 == 1 -- > round 1.2 == 1 -- > round 1.5 == 2 -- > round 1.8 == 2 -- -- > round -1.2 == -1 -- > round -1.5 == -1 -- > round -1.8 == -2 round :: Float -> Int round = Prelude.round -- | Floor function, rounding down. -- -- > floor 1.0 == 1 -- > floor 1.2 == 1 -- > floor 1.5 == 1 -- > floor 1.8 == 1 -- -- > floor -1.2 == -2 -- > floor -1.5 == -2 -- > floor -1.8 == -2 floor :: Float -> Int floor = Prelude.floor -- | Ceiling function, rounding up. -- -- > ceiling 1.0 == 1 -- > ceiling 1.2 == 2 -- > ceiling 1.5 == 2 -- > ceiling 1.8 == 2 -- -- > ceiling -1.2 == -1 -- > ceiling -1.5 == -1 -- > ceiling -1.8 == -1 ceiling :: Float -> Int ceiling = Prelude.ceiling -- | Truncate a number, rounding towards zero. -- -- > truncate 1.0 == 1 -- > truncate 1.2 == 1 -- > truncate 1.5 == 1 -- > truncate 1.8 == 1 -- -- > truncate -1.2 == -1 -- > truncate -1.5 == -1 -- > truncate -1.8 == -1 truncate :: Float -> Int truncate = Prelude.truncate -- | Check if values are “the same”. -- -- Breaking from Elm, this relies on Haskell's @Eq@ typeclass. For example: -- -- > data Foo = Bar | Baz deriving (Eq) (==) :: Prelude.Eq a => a -> a -> Bool (==) = (Prelude.==) -- | Check if values are not “the same”. -- -- Like with @(==)@, this relies on Haskell's @Eq@ typeclass. -- -- So @(a /= b)@ is the same as @(not (a == b))@. (/=) :: Prelude.Eq a => a -> a -> Bool (/=) = (Prelude./=) -- | (<) :: Prelude.Ord comparable => comparable -> comparable -> Bool (<) = (Prelude.<) -- | (>) :: Prelude.Ord comparable => comparable -> comparable -> Bool (>) = (Prelude.>) -- | (<=) :: Prelude.Ord comparable => comparable -> comparable -> Bool (<=) = (Prelude.<=) -- | (>=) :: Prelude.Ord comparable => comparable -> comparable -> Bool (>=) = (Prelude.>=) -- | Find the larger of two comparables. -- -- > max 42 12345678 == 12345678 -- > max "abc" "xyz" == "xyz" max :: Prelude.Ord comparable => comparable -> comparable -> comparable max = Prelude.max -- | Find the smaller of two comparables. -- -- > min 42 12345678 == 42 -- > min "abc" "xyz" == "abc" min :: Prelude.Ord comparable => comparable -> comparable -> comparable min = Prelude.min -- | Compare any two comparable values. Comparable values include @String@, -- @Char@, @Int@, @Float@, or a list or tuple containing comparable values. These -- are also the only values that work as @Dict@ keys or @Set@ members. -- -- > compare 3 4 == LT -- > compare 4 4 == EQ -- > compare 5 4 == GT compare :: Prelude.Ord comparable => comparable -> comparable -> Order compare = Prelude.compare -- | Represents the relative ordering of two things. -- The relations are less than, equal to, and greater than. type Order = Prelude.Ordering -- | A “Boolean” value. It can either be @True@ or @False@. -- -- __Note:__ Programmers coming from JavaScript, Java, etc. tend to reach for boolean values way too often in Elm. Using a [union type](https://guide.elm-lang.org/types/union_types.html) is often clearer and more reliable. You can learn more about this from Jeremy [here](https://youtu.be/6TDKHGtAxeg?t=1m25s) or from Richard [here](https://youtu.be/IcgmSRJHu_8?t=1m14s). type Bool = Prelude.Bool -- | Negate a boolean value. -- -- > not True == False -- > not False == True not :: Bool -> Bool not = Prelude.not -- | The logical AND operator. @True@ if both inputs are @True@. -- -- > True && True == True -- > True && False == False -- > False && True == False -- > False && False == False (&&) :: Bool -> Bool -> Bool (&&) = (Prelude.&&) -- | The logical OR operator. @True@ if one or both inputs are @True@. -- -- > True || True == True -- > True || False == True -- > False || True == True -- > False || False == False (||) :: Bool -> Bool -> Bool (||) = (Prelude.||) -- | The exclusive-or operator. @True@ if exactly one input is @True@. -- -- > xor True True == False -- > xor True False == True -- > xor False True == True -- > xor False False == False xor :: Bool -> Bool -> Bool xor = Data.Bits.xor -- | Put two appendable things together. This includes strings, lists, and text. -- -- > "hello" ++ "world" == "helloworld" -- > [1,1,2] ++ [3,5,8] == [1,1,2,3,5,8] (++) :: Prelude.Semigroup appendable => appendable -> appendable -> appendable (++) = (Prelude.<>) -- | Perform [modular arithmetic](https://en.wikipedia.org/wiki/Modular_arithmetic). -- A common trick is to use (n mod 2) to detect even and odd numbers: -- -- > modBy 2 0 == 0 -- > modBy 2 1 == 1 -- > modBy 2 2 == 0 -- > modBy 2 3 == 1 -- -- Our @modBy@ function works in the typical mathematical way when you run into -- negative numbers: -- -- > List.map (modBy 4) [ -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 ] -- > -- [ 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1 ] -- -- Use '@remainderBy@' for a different treatment of negative numbers, or read Daan Leijen’s [Division and Modulus for Computer Scientists](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf) for more information. modBy :: Int -> Int -> Int modBy = Prelude.flip Prelude.mod -- | Get the remainder after division. Here are bunch of examples of dividing by four: -- -- > List.map (remainderBy 4) [ -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 ] -- > -- [ -1, 0, -3, -2, -1, 0, 1, 2, 3, 0, 1 ] -- -- Use '@modBy@' for a different treatment of negative numbers, or read Daan Leijen’s [Division and Modulus for Computer Scientists](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf) for more information. remainderBy :: Int -> Int -> Int remainderBy = Prelude.flip Prelude.rem -- | Negate a number. -- -- negate 42 == -42 -- negate -42 == 42 -- negate 0 == 0 negate :: Prelude.Num number => number -> number negate = Prelude.negate -- | Get the [absolute value](https://en.wikipedia.org/wiki/Absolute_value) of -- a number. -- -- > abs 16 == 16 -- > abs -4 == 4 -- > abs -8.5 == 8.5 -- > abs 3.14 == 3.14 abs :: Prelude.Num number => number -> number abs = Prelude.abs -- | Clamps a number within a given range. With the expression -- @clamp 100 200 x@ the results are as follows: -- -- > 100 if x < 100 -- > x if 100 <= x < 200 -- > 200 if 200 <= x clamp :: Prelude.Ord number => number -> number -> number -> number clamp low high number | number < low = low | number > high = high | otherwise = number -- | Take the square root of a number. -- -- > sqrt 4 == 2 -- > sqrt 9 == 3 -- > sqrt 16 == 4 -- > sqrt 25 == 5 sqrt :: Float -> Float sqrt = Prelude.sqrt -- | Calculate the logarithm of a number with a given base. -- -- > logBase 10 100 == 2 -- > logBase 2 256 == 8 logBase :: Float -> Float -> Float logBase = Prelude.logBase -- | An approximation of e. e :: Float e = Prelude.exp 1 -- | Convert radians to standard Elm angles (radians). -- -- > radians pi == 3.141592653589793 radians :: Float -> Float radians angleInRadians = angleInRadians -- | Convert degrees to standard Elm angles (radians). -- -- > degrees 180 == 3.141592653589793 degrees :: Float -> Float degrees angleInDegrees = (angleInDegrees * pi) / 180 -- | Convert turns to standard Elm angles (radians). One turn is equal to 360°. -- -- > turns (1/2) == 3.141592653589793 turns :: Float -> Float turns angleInTurns = (2 * pi) * angleInTurns -- | An approximation of pi. pi :: Float pi = Prelude.pi -- | Figure out the cosine given an angle in radians. -- -- > cos (degrees 60) == 0.5000000000000001 -- > cos (turns (1/6)) == 0.5000000000000001 -- > cos (radians (pi/3)) == 0.5000000000000001 -- > cos (pi/3) == 0.5000000000000001 cos :: Float -> Float cos = Prelude.cos -- | Figure out the sine given an angle in radians. -- -- > sin (degrees 30) == 0.49999999999999994 -- > sin (turns (1/12)) == 0.49999999999999994 -- > sin (radians (pi/6)) == 0.49999999999999994 -- > sin (pi/6) == 0.49999999999999994 sin :: Float -> Float sin = Prelude.sin -- | Figure out the tangent given an angle in radians. -- -- > tan (degrees 45) == 0.9999999999999999 -- > tan (turns (1/8)) == 0.9999999999999999 -- > tan (radians (pi/4)) == 0.9999999999999999 -- > tan (pi/4) == 0.9999999999999999 tan :: Float -> Float tan = Prelude.tan -- | Figure out the arccosine for @adjacent / hypotenuse@ in radians: -- -- > acos (1/2) == 1.0471975511965979 -- 60° or pi/3 radians acos :: Float -> Float acos = Prelude.acos -- | Figure out the arcsine for @opposite / hypotenuse@ in radians: -- -- > asin (1/2) == 0.5235987755982989 -- 30° or pi/6 radians asin :: Float -> Float asin = Prelude.asin -- | This helps you find the angle (in radians) to an @(x,y)@ coordinate, but -- in a way that is rarely useful in programming. __You probably want -- 'atan2' instead!__ -- -- This version takes @y/x@ as its argument, so there is no way to know whether -- the negative signs comes from the @y@ or @x@ value. So as we go counter-clockwise -- around the origin from point @(1,1)@ to @(1,-1)@ to @(-1,-1)@ to @(-1,1)@ we do -- not get angles that go in the full circle: -- -- > atan ( 1 / 1 ) == 0.7853981633974483 -- 45° or pi/4 radians -- > atan ( 1 / -1 ) == -0.7853981633974483 -- 315° or 7*pi/4 radians -- > atan ( -1 / -1 ) == 0.7853981633974483 -- 45° or pi/4 radians -- > atan ( -1 / 1 ) == -0.7853981633974483 -- 315° or 7*pi/4 radians -- -- Notice that everything is between @pi/2@ and @-pi/2@. That is pretty useless -- for figuring out angles in any sort of visualization, so again, check out -- 'atan2' instead! atan :: Float -> Float atan = Prelude.atan -- | This helps you find the angle (in radians) to an @(x,y)@ coordinate. -- So rather than saying @atan (y/x)@ you say @atan2 y x@ and you can get a full -- range of angles: -- -- > atan2 1 1 == 0.7853981633974483 -- 45° or pi/4 radians -- > atan2 1 -1 == 2.356194490192345 -- 135° or 3*pi/4 radians -- > atan2 -1 -1 == -2.356194490192345 -- 225° or 5*pi/4 radians -- > atan2 -1 1 == -0.7853981633974483 -- 315° or 7*pi/4 radians atan2 :: Float -> Float -> Float atan2 = Prelude.atan2 -- | Convert Cartesian coordinates (x,y) to polar coordinates (r,θ). -- -- > toPolar (3, 4) == ( 5, 0.9272952180016122) -- > toPolar (5,12) == (13, 1.1760052070951352) toPolar :: (Float, Float) -> (Float, Float) toPolar (x, y) = ( sqrt ((x * x) + (y * y)), atan2 y x ) -- | Convert polar coordinates (r,θ) to Cartesian coordinates (x,y). -- -- > fromPolar (sqrt 2, degrees 45) == (1, 1) fromPolar :: (Float, Float) -> (Float, Float) fromPolar (radius, theta) = ( radius * cos theta, radius * sin theta ) -- | Determine whether a float is an undefined or unrepresentable number. -- NaN stands for *not a number* and it is [a standardized part of floating point -- numbers](https://en.wikipedia.org/wiki/NaN). -- -- > isNaN (0/0) == True -- > isNaN (sqrt -1) == True -- > isNaN (1/0) == False -- infinity is a number -- > isNaN 1 == False isNaN :: Float -> Bool isNaN = Prelude.isNaN -- | Determine whether a float is positive or negative infinity. -- -- > isInfinite (0/0) == False -- > isInfinite (sqrt -1) == False -- > isInfinite (1/0) == True -- > isInfinite 1 == False -- -- Notice that NaN is not infinite! For float @n@ to be finite implies that -- @not (isInfinite n || isNaN n)@ evaluates to @True@. isInfinite :: Float -> Bool isInfinite = Prelude.isInfinite -- | Given a value, returns exactly the same value. This is called -- [the identity function](https://en.wikipedia.org/wiki/Identity_function). identity :: a -> a identity x = x -- | Create a function that *always* returns the same value. Useful with -- functions like @map@: -- -- > List.map (always 0) [1,2,3,4,5] == [0,0,0,0,0] -- -- > -- List.map (\_ -> 0) [1,2,3,4,5] == [0,0,0,0,0] -- > -- always = (\x _ -> x) always :: a -> b -> a always a _ = a -- | Saying @f <| x@ is exactly the same as @f x@. -- -- It can help you avoid parentheses, which can be nice sometimes. Maybe you want -- to apply a function to a @case@ expression? That sort of thing. (<|) :: (a -> b) -> a -> b f <| x = f x -- | Saying @x |> f@ is exactly the same as @f x@. -- -- It is called the “pipe” operator because it lets you write “pipelined” code. -- For example, say we have a @sanitize@ function for turning user input into -- integers: -- -- > -- BEFORE -- > sanitize :: String -> Maybe Int -- > sanitize input = -- > String.toInt (String.trim input) -- -- We can rewrite it like this: -- -- > -- AFTER -- > sanitize :: String -> Maybe Int -- > sanitize input = -- > input -- > |> String.trim -- > |> String.toInt -- -- Totally equivalent! I recommend trying to rewrite code that uses @x |> f@ -- into code like @f x@ until there are no pipes left. That can help you build -- your intuition. -- -- __Note:__ This can be overused! I think folks find it quite neat, but when you -- have three or four steps, the code often gets clearer if you break out a -- top-level helper function. Now the transformation has a name. The arguments are -- named. It has a type annotation. It is much more self-documenting that way! -- Testing the logic gets easier too. Nice side benefit! (|>) :: a -> (a -> b) -> b x |> f = f x -- | Function composition, passing results along in the suggested direction. For -- example, the following code checks if the square root of a number is odd: -- -- > not << isEven << sqrt -- -- You can think of this operator as equivalent to the following: -- -- > (g << f) == (\x -> g (f x)) -- -- So our example expands out to something like this: -- -- > \n -> not (isEven (sqrt n)) (<<) :: (b -> c) -> (a -> b) -> (a -> c) (<<) = (Prelude..) -- | Function composition, passing results along in the suggested direction. For -- example, the following code checks if the square root of a number is odd: -- -- > sqrt >> isEven >> not (>>) :: (a -> b) -> (b -> c) -> (a -> c) (>>) = Prelude.flip (Prelude..) -- | A value that can never happen! For context: -- -- - The boolean type @Bool@ has two values: @True@ and @False@ -- - The unit type @()@ has one value: @()@ -- - The never type @Never@ has no values! -- -- You may see it in the wild in @Html Never@ which means this HTML will never -- produce any messages. You would need to write an event handler like -- @onClick ??? :: Attribute Never@ but how can we fill in the question marks?! -- So there cannot be any event handlers on that HTML. -- -- You may also see this used with tasks that never fail, like @Task Never ()@. -- -- The @Never@ type is useful for restricting *arguments* to a function. Maybe my -- API can only accept HTML without event handlers, so I require @Html Never@ and -- users can give @Html msg@ and everything will go fine. Generally speaking, you -- do not want @Never@ in your return types though. type Never = Data.Void.Void -- | A function that can never be called. Seems extremely pointless, but it -- *can* come in handy. Imagine you have some HTML that should never produce any -- messages. And say you want to use it in some other HTML that *does* produce -- messages. You could say: -- -- > import Html exposing (..) -- > -- > embedHtml :: Html Never -> Html msg -- > embedHtml staticStuff = -- > div [] -- > [ text "hello" -- > , Html.map never staticStuff -- > ] -- -- So the @never@ function is basically telling the type system, make sure no one -- ever calls me! never :: Never -> a never = Data.Void.absurd