1-- | This module provides documentation for the builtin Prim modules. 2module Language.PureScript.Docs.Prim 3 ( primDocsModule 4 , primRowDocsModule 5 , primTypeErrorDocsModule 6 , primModules 7 ) where 8 9import Prelude.Compat hiding (fail) 10import Data.Functor (($>)) 11import Data.Text (Text) 12import qualified Data.Text as T 13import qualified Data.Map as Map 14import Language.PureScript.Docs.Types 15 16import qualified Language.PureScript.Crash as P 17import qualified Language.PureScript.Environment as P 18import qualified Language.PureScript.Names as P 19 20primModules :: [Module] 21primModules = 22 [ primDocsModule 23 , primBooleanDocsModule 24 , primCoerceDocsModule 25 , primOrderingDocsModule 26 , primRowDocsModule 27 , primRowListDocsModule 28 , primSymbolDocsModule 29 , primTypeErrorDocsModule 30 ] 31 32primDocsModule :: Module 33primDocsModule = Module 34 { modName = P.moduleNameFromString "Prim" 35 , modComments = Just $ T.unlines 36 [ "The `Prim` module is embedded in the PureScript compiler in order to provide compiler support for certain types — for example, value literals, or syntax sugar. It is implicitly imported unqualified in every module except those that list it as a qualified import." 37 , "" 38 , "`Prim` does not include additional built-in types and kinds that are defined deeper in the compiler such as Type wildcards (e.g. `f :: _ -> Int`) and Quantified Types. Rather, these are documented in [the PureScript language reference](https://github.com/purescript/documentation/blob/master/language/Types.md)." 39 ] 40 , modDeclarations = 41 [ function 42 , array 43 , record 44 , number 45 , int 46 , string 47 , char 48 , boolean 49 , partial 50 , kindType 51 , kindConstraint 52 , kindSymbol 53 , kindRow 54 ] 55 , modReExports = [] 56 } 57 58primBooleanDocsModule :: Module 59primBooleanDocsModule = Module 60 { modName = P.moduleNameFromString "Prim.Boolean" 61 , modComments = Just "The Prim.Boolean module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains a type level `Boolean` data structure." 62 , modDeclarations = 63 [ booleanTrue 64 , booleanFalse 65 ] 66 , modReExports = [] 67 } 68 69primCoerceDocsModule :: Module 70primCoerceDocsModule = Module 71 { modName = P.moduleNameFromString "Prim.Coerce" 72 , modComments = Just "The Prim.Coerce module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains an automatically solved type class for coercing types that have provably-identical runtime representations with [purescript-safe-coerce](https://pursuit.purescript.org/packages/purescript-safe-coerce)." 73 , modDeclarations = 74 [ coercible 75 ] 76 , modReExports = [] 77 } 78 79primOrderingDocsModule :: Module 80primOrderingDocsModule = Module 81 { modName = P.moduleNameFromString "Prim.Ordering" 82 , modComments = Just "The Prim.Ordering module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains a type level `Ordering` data structure." 83 , modDeclarations = 84 [ kindOrdering 85 , orderingLT 86 , orderingEQ 87 , orderingGT 88 ] 89 , modReExports = [] 90 } 91 92primRowDocsModule :: Module 93primRowDocsModule = Module 94 { modName = P.moduleNameFromString "Prim.Row" 95 , modComments = Just "The Prim.Row module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains automatically solved type classes for working with row types." 96 , modDeclarations = 97 [ union 98 , nub 99 , lacks 100 , rowCons 101 ] 102 , modReExports = [] 103 } 104 105primRowListDocsModule :: Module 106primRowListDocsModule = Module 107 { modName = P.moduleNameFromString "Prim.RowList" 108 , modComments = Just "The Prim.RowList module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains a type level list (`RowList`) that represents an ordered view of a row of types." 109 , modDeclarations = 110 [ kindRowList 111 , rowListCons 112 , rowListNil 113 , rowToList 114 ] 115 , modReExports = [] 116 } 117 118primSymbolDocsModule :: Module 119primSymbolDocsModule = Module 120 { modName = P.moduleNameFromString "Prim.Symbol" 121 , modComments = Just "The Prim.Symbol module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains automatically solved type classes for working with `Symbols`." 122 , modDeclarations = 123 [ symbolAppend 124 , symbolCompare 125 , symbolCons 126 ] 127 , modReExports = [] 128 } 129 130primTypeErrorDocsModule :: Module 131primTypeErrorDocsModule = Module 132 { modName = P.moduleNameFromString "Prim.TypeError" 133 , modComments = Just "The Prim.TypeError module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains type classes that provide custom type error and warning functionality." 134 , modDeclarations = 135 [ warn 136 , fail 137 , kindDoc 138 , textDoc 139 , quoteDoc 140 , quoteLabelDoc 141 , besideDoc 142 , aboveDoc 143 ] 144 , modReExports = [] 145 } 146 147type NameGen a = Text -> P.Qualified (P.ProperName a) 148 149unsafeLookupOf 150 :: forall v (a :: P.ProperNameType) 151 . NameGen a 152 -> Map.Map (P.Qualified (P.ProperName a)) v 153 -> String 154 -> Text 155 -> v 156unsafeLookupOf k m errorMsg name = go name 157 where 158 go = fromJust' . flip Map.lookup m . k 159 160 fromJust' (Just x) = x 161 fromJust' _ = P.internalError $ errorMsg ++ show name 162 163lookupPrimTypeKindOf 164 :: NameGen 'P.TypeName 165 -> Text 166 -> Type' 167lookupPrimTypeKindOf k = ($> ()) . fst . unsafeLookupOf k 168 ( P.primTypes <> 169 P.primBooleanTypes <> 170 P.primOrderingTypes <> 171 P.primRowTypes <> 172 P.primRowListTypes <> 173 P.primTypeErrorTypes 174 ) "Docs.Prim: No such Prim type: " 175 176primType :: Text -> Text -> Declaration 177primType = primTypeOf P.primName 178 179primTypeOf :: NameGen 'P.TypeName -> Text -> Text -> Declaration 180primTypeOf gen title comments = Declaration 181 { declTitle = title 182 , declComments = Just comments 183 , declSourceSpan = Nothing 184 , declChildren = [] 185 , declInfo = ExternDataDeclaration (lookupPrimTypeKindOf gen title) 186 , declKind = Nothing 187 } 188 189-- | Lookup the TypeClassData of a Prim class. This function is specifically 190-- not exported because it is partial. 191lookupPrimClassOf :: NameGen 'P.ClassName -> Text -> P.TypeClassData 192lookupPrimClassOf g = unsafeLookupOf g 193 ( P.primClasses <> 194 P.primCoerceClasses <> 195 P.primRowClasses <> 196 P.primRowListClasses <> 197 P.primSymbolClasses <> 198 P.primTypeErrorClasses 199 ) "Docs.Prim: No such Prim class: " 200 201primClass :: Text -> Text -> Declaration 202primClass = primClassOf P.primName 203 204primClassOf :: NameGen 'P.ClassName -> Text -> Text -> Declaration 205primClassOf gen title comments = Declaration 206 { declTitle = title 207 , declComments = Just comments 208 , declSourceSpan = Nothing 209 , declChildren = [] 210 , declInfo = 211 let 212 tcd = lookupPrimClassOf gen title 213 args = fmap (fmap ($> ())) <$> P.typeClassArguments tcd 214 superclasses = ($> ()) <$> P.typeClassSuperclasses tcd 215 fundeps = convertFundepsToStrings args (P.typeClassDependencies tcd) 216 in 217 TypeClassDeclaration args superclasses fundeps 218 , declKind = Nothing 219 } 220 221kindType :: Declaration 222kindType = primType "Type" $ T.unlines 223 [ "`Type` is the kind of all proper types: those that classify value-level terms." 224 , "For example the type `Boolean` has kind `Type`; denoted by `Boolean :: Type`." 225 ] 226 227kindConstraint :: Declaration 228kindConstraint = primType "Constraint" $ T.unlines 229 [ "`Constraint` is the kind of type class constraints." 230 , "For example, a type class declaration like this:" 231 , "" 232 , " class Semigroup a where" 233 , " append :: a -> a -> a" 234 , "" 235 , "has the kind signature:" 236 , "" 237 , " class Semigroup :: Type -> Constraint" 238 ] 239 240kindSymbol :: Declaration 241kindSymbol = primType "Symbol" $ T.unlines 242 [ "`Symbol` is the kind of type-level strings." 243 , "" 244 , "Construct types of this kind using the same literal syntax as documented" 245 , "for strings." 246 ] 247 248kindRow :: Declaration 249kindRow = primType "Row" $ T.unlines 250 [ "`Row` is the kind constructor of label-indexed types which map type-level strings to other types." 251 , "For example, the kind of `Record` is `Row Type -> Type`, mapping field names to values." 252 ] 253 254function :: Declaration 255function = primType "Function" $ T.unlines 256 [ "A function, which takes values of the type specified by the first type" 257 , "parameter, and returns values of the type specified by the second." 258 , "In the JavaScript backend, this is a standard JavaScript Function." 259 , "" 260 , "The type constructor `(->)` is syntactic sugar for this type constructor." 261 , "It is recommended to use `(->)` rather than `Function`, where possible." 262 , "" 263 , "That is, prefer this:" 264 , "" 265 , " f :: Number -> Number" 266 , "" 267 , "to either of these:" 268 , "" 269 , " f :: Function Number Number" 270 , " f :: (->) Number Number" 271 ] 272 273array :: Declaration 274array = primType "Array" $ T.unlines 275 [ "An Array: a data structure supporting efficient random access. In" 276 , "the JavaScript backend, values of this type are represented as JavaScript" 277 , "Arrays at runtime." 278 , "" 279 , "Construct values using literals:" 280 , "" 281 , " x = [1,2,3,4,5] :: Array Int" 282 ] 283 284record :: Declaration 285record = primType "Record" $ T.unlines 286 [ "The type of records whose fields are known at compile time. In the" 287 , "JavaScript backend, values of this type are represented as JavaScript" 288 , "Objects at runtime." 289 , "" 290 , "The type signature here means that the `Record` type constructor takes" 291 , "a row of concrete types. For example:" 292 , "" 293 , " type Person = Record (name :: String, age :: Number)" 294 , "" 295 , "The syntactic sugar with curly braces `{ }` is generally preferred, though:" 296 , "" 297 , " type Person = { name :: String, age :: Number }" 298 , "" 299 , "The row associates a type to each label which appears in the record." 300 , "" 301 , "_Technical note_: PureScript allows duplicate labels in rows, and the" 302 , "meaning of `Record r` is based on the _first_ occurrence of each label in" 303 , "the row `r`." 304 ] 305 306number :: Declaration 307number = primType "Number" $ T.unlines 308 [ "A double precision floating point number (IEEE 754)." 309 , "" 310 , "Construct values of this type with literals:" 311 , "" 312 , " y = 35.23 :: Number" 313 , " z = 1.224e6 :: Number" 314 ] 315 316int :: Declaration 317int = primType "Int" $ T.unlines 318 [ "A 32-bit signed integer. See the purescript-integers package for details" 319 , "of how this is accomplished when compiling to JavaScript." 320 , "" 321 , "Construct values of this type with literals:" 322 , "" 323 , " x = 23 :: Int" 324 ] 325 326string :: Declaration 327string = primType "String" $ T.unlines 328 [ "A String. As in JavaScript, String values represent sequences of UTF-16" 329 , "code units, which are not required to form a valid encoding of Unicode" 330 , "text (for example, lone surrogates are permitted)." 331 , "" 332 , "Construct values of this type with literals, using double quotes `\"`:" 333 , "" 334 , " x = \"hello, world\" :: String" 335 , "" 336 , "Multi-line string literals are also supported with triple quotes (`\"\"\"`)." 337 ] 338 339char :: Declaration 340char = primType "Char" $ T.unlines 341 [ "A single character (UTF-16 code unit). The JavaScript representation is a" 342 , "normal String, which is guaranteed to contain one code unit. This means" 343 , "that astral plane characters (i.e. those with code point values greater" 344 , "than 0xFFFF) cannot be represented as Char values." 345 , "" 346 , "Construct values of this type with literals, using single quotes `'`:" 347 , "" 348 , " x = 'a' :: Char" 349 ] 350 351boolean :: Declaration 352boolean = primType "Boolean" $ T.unlines 353 [ "A JavaScript Boolean value." 354 , "" 355 , "Construct values of this type with the literals `true` and `false`." 356 ] 357 358partial :: Declaration 359partial = primClass "Partial" $ T.unlines 360 [ "The Partial type class is used to indicate that a function is *partial,*" 361 , "that is, it is not defined for all inputs. In practice, attempting to use" 362 , "a partial function with a bad input will usually cause an error to be" 363 , "thrown, although it is not safe to assume that this will happen in all" 364 , "cases. For more information, see" 365 , "[purescript-partial](https://pursuit.purescript.org/packages/purescript-partial/)." 366 ] 367 368booleanTrue :: Declaration 369booleanTrue = primTypeOf (P.primSubName "Boolean") "True" $ T.unlines 370 [ "The 'True' boolean type." 371 ] 372 373booleanFalse :: Declaration 374booleanFalse = primTypeOf (P.primSubName "Boolean") "False" $ T.unlines 375 [ "The 'False' boolean type." 376 ] 377 378coercible :: Declaration 379coercible = primClassOf (P.primSubName "Coerce") "Coercible" $ T.unlines 380 [ "Coercible is a two-parameter type class that has instances for types `a`" 381 , "and `b` if the compiler can infer that they have the same representation." 382 , "Coercible constraints are solved according to the following rules:" 383 , "" 384 , "* _reflexivity_, any type has the same representation as itself:" 385 , "`Coercible a a` holds." 386 , "" 387 , "* _symmetry_, if a type `a` can be coerced to some other type `b`, then `b`" 388 , "can also be coerced back to `a`: `Coercible a b` implies `Coercible b a`." 389 , "" 390 , "* _transitivity_, if a type `a` can be coerced to some other type `b` which" 391 , "can be coerced to some other type `c`, then `a` can also be coerced to `c`:" 392 , "`Coercible a b` and `Coercible b c` imply `Coercible a c`." 393 , "" 394 , "* Newtypes can be freely wrapped and unwrapped when their constructor is" 395 , "in scope:" 396 , "" 397 , " newtype Age = Age Int" 398 , "" 399 , "`Coercible Int Age` and `Coercible Age Int` hold since `Age` has the same" 400 , "runtime representation than `Int`." 401 , "" 402 , "Newtype constructors have to be in scope to preserve abstraction. It's" 403 , "common to declare a newtype to encode some invariants (non emptiness of" 404 , "arrays with `Data.Array.NonEmpty.NonEmptyArray` for example), hide its" 405 , "constructor and export smart constructors instead. Without this restriction," 406 , "the guarantees provided by such newtypes would be void." 407 , "" 408 , "* If none of the above are applicable, two types of kind `Type` may be" 409 , "coercible, but only if their heads are the same. For example," 410 , "`Coercible (Maybe a) (Either a b)` does not hold because `Maybe` and" 411 , "`Either` are different. Those types don't share a common runtime" 412 , "representation so coercing between them would be unsafe. In addition their" 413 , "arguments may need to be identical or coercible, depending on the _roles_" 414 , "of the head's type parameters. Roles are documented in [the PureScript" 415 , "language reference](https://github.com/purescript/documentation/blob/master/language/Roles.md)." 416 , "" 417 , "Coercible being polykinded, we can also coerce more than types of kind `Type`:" 418 , "" 419 , "* Rows are coercible when they have the same labels, when the corresponding" 420 , "pairs of types are coercible and when their tails are coercible:" 421 , "`Coercible ( label :: a | r ) ( label :: b | s )` holds when" 422 , "`Coercible a b` and `Coercible r s` do. Closed rows cannot be coerced to" 423 , "open rows." 424 , "" 425 , "* Higher kinded types are coercible if they are coercible when fully" 426 , "saturated: `Coercible (f :: _ -> Type) (g :: _ -> Type)` holds when" 427 , "`Coercible (f a) (g a)` does." 428 , "" 429 , "This rule may seem puzzling since there is no term of type `_ -> Type` to" 430 , "apply `coerce` to, but it is necessary when coercing types with higher" 431 , "kinded parameters." 432 ] 433 434kindOrdering :: Declaration 435kindOrdering = primTypeOf (P.primSubName "Ordering") "Ordering" $ T.unlines 436 [ "The `Ordering` kind represents the three possibilities of comparing two" 437 , "types of the same kind: `LT` (less than), `EQ` (equal to), and" 438 , "`GT` (greater than)." 439 ] 440 441orderingLT :: Declaration 442orderingLT = primTypeOf (P.primSubName "Ordering") "LT" $ T.unlines 443 [ "The 'less than' ordering type." 444 ] 445 446orderingEQ :: Declaration 447orderingEQ = primTypeOf (P.primSubName "Ordering") "EQ" $ T.unlines 448 [ "The 'equal to' ordering type." 449 ] 450 451orderingGT :: Declaration 452orderingGT = primTypeOf (P.primSubName "Ordering") "GT" $ T.unlines 453 [ "The 'greater than' ordering type." 454 ] 455 456union :: Declaration 457union = primClassOf (P.primSubName "Row") "Union" $ T.unlines 458 [ "The Union type class is used to compute the union of two rows of types" 459 , "(left-biased, including duplicates)." 460 , "" 461 , "The third type argument represents the union of the first two." 462 ] 463 464nub :: Declaration 465nub = primClassOf (P.primSubName "Row") "Nub" $ T.unlines 466 [ "The Nub type class is used to remove duplicate labels from rows." 467 ] 468 469lacks :: Declaration 470lacks = primClassOf (P.primSubName "Row") "Lacks" $ T.unlines 471 [ "The Lacks type class asserts that a label does not occur in a given row." 472 ] 473 474rowCons :: Declaration 475rowCons = primClassOf (P.primSubName "Row") "Cons" $ T.unlines 476 [ "The Cons type class is a 4-way relation which asserts that one row of" 477 , "types can be obtained from another by inserting a new label/type pair on" 478 , "the left." 479 ] 480 481kindRowList :: Declaration 482kindRowList = primTypeOf (P.primSubName "RowList") "RowList" $ T.unlines 483 [ "A type level list representation of a row of types." 484 ] 485 486rowListCons :: Declaration 487rowListCons = primTypeOf (P.primSubName "RowList") "Cons" $ T.unlines 488 [ "Constructs a new `RowList` from a label, a type, and an existing tail" 489 , "`RowList`. E.g: `Cons \"x\" Int (Cons \"y\" Int Nil)`." 490 ] 491 492rowListNil :: Declaration 493rowListNil = primTypeOf (P.primSubName "RowList") "Nil" $ T.unlines 494 [ "The empty `RowList`." 495 ] 496 497rowToList :: Declaration 498rowToList = primClassOf (P.primSubName "RowList") "RowToList" $ T.unlines 499 [ "Compiler solved type class for generating a `RowList` from a closed row" 500 , "of types. Entries are sorted by label and duplicates are preserved in" 501 , "the order they appeared in the row." 502 ] 503 504symbolAppend :: Declaration 505symbolAppend = primClassOf (P.primSubName "Symbol") "Append" $ T.unlines 506 [ "Compiler solved type class for appending `Symbol`s together." 507 ] 508 509symbolCompare :: Declaration 510symbolCompare = primClassOf (P.primSubName "Symbol") "Compare" $ T.unlines 511 [ "Compiler solved type class for comparing two `Symbol`s." 512 , "Produces an `Ordering`." 513 ] 514 515symbolCons :: Declaration 516symbolCons = primClassOf (P.primSubName "Symbol") "Cons" $ T.unlines 517 [ "Compiler solved type class for either splitting up a symbol into its" 518 , "head and tail or for combining a head and tail into a new symbol." 519 , "Requires the head to be a single character and the combined string" 520 , "cannot be empty." 521 ] 522 523fail :: Declaration 524fail = primClassOf (P.primSubName "TypeError") "Fail" $ T.unlines 525 [ "The Fail type class is part of the custom type errors feature. To provide" 526 , "a custom type error when someone tries to use a particular instance," 527 , "write that instance out with a Fail constraint." 528 , "" 529 , "For more information, see" 530 , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)." 531 ] 532 533warn :: Declaration 534warn = primClassOf (P.primSubName "TypeError") "Warn" $ T.unlines 535 [ "The Warn type class allows a custom compiler warning to be displayed." 536 , "" 537 , "For more information, see" 538 , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)." 539 ] 540 541kindDoc :: Declaration 542kindDoc = primTypeOf (P.primSubName "TypeError") "Doc" $ T.unlines 543 [ "`Doc` is the kind of type-level documents." 544 , "" 545 , "This kind is used with the `Fail` and `Warn` type classes." 546 , "Build up a `Doc` with `Text`, `Quote`, `QuoteLabel`, `Beside`, and `Above`." 547 ] 548 549textDoc :: Declaration 550textDoc = primTypeOf (P.primSubName "TypeError") "Text" $ T.unlines 551 [ "The Text type constructor makes a Doc from a Symbol" 552 , "to be used in a custom type error." 553 , "" 554 , "For more information, see" 555 , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)." 556 ] 557 558quoteDoc :: Declaration 559quoteDoc = primTypeOf (P.primSubName "TypeError") "Quote" $ T.unlines 560 [ "The Quote type constructor renders any concrete type as a Doc" 561 , "to be used in a custom type error." 562 , "" 563 , "For more information, see" 564 , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)." 565 ] 566 567quoteLabelDoc :: Declaration 568quoteLabelDoc = primTypeOf (P.primSubName "TypeError") "QuoteLabel" $ T.unlines 569 [ "The `QuoteLabel` type constructor will produce a `Doc` when given a `Symbol`. When the resulting `Doc` is rendered" 570 , "for a `Warn` or `Fail` constraint, a syntactically valid label will be produced, escaping with quotes as needed." 571 , "" 572 , "For more information, see" 573 , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)." 574 ] 575 576besideDoc :: Declaration 577besideDoc = primTypeOf (P.primSubName "TypeError") "Beside" $ T.unlines 578 [ "The Beside type constructor combines two Docs horizontally" 579 , "to be used in a custom type error." 580 , "" 581 , "For more information, see" 582 , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)." 583 ] 584 585aboveDoc :: Declaration 586aboveDoc = primTypeOf (P.primSubName "TypeError") "Above" $ T.unlines 587 [ "The Above type constructor combines two Docs vertically" 588 , "in a custom type error." 589 , "" 590 , "For more information, see" 591 , "[the Custom Type Errors guide](https://github.com/purescript/documentation/blob/master/guides/Custom-Type-Errors.md)." 592 ] 593