Skip to content

Commit 96227ca

Browse files
authored
Merge pull request #43 from mlabs-haskell/standards-update
Update STANDARDS doc with latest changes from Koz
2 parents 145bae6 + c59726a commit 96227ca

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

STANDARDS.md

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ Exceptions are granted when:
269269
modules); or
270270
* We have to import a data type qualified as well.
271271

272+
Qualified imports of multiple modules MUST NOT be imported under the same name.
273+
Thus, the following is wrong:
274+
275+
```haskell
276+
import qualified Foo.Bar as Baz
277+
import qualified Foo.Quux as Baz
278+
```
279+
272280
### Justification
273281

274282
Explicit export lists are an immediate, clear and obvious indication of what
@@ -298,12 +306,16 @@ qualified, is good practice, and saves on a lot of prefixing.
298306

299307
## Plutus module import naming conventions
300308

301-
In addition to the general module import rules, we should follow some conventions on how we import the Plutus API modules, allowing for some flexibility depending on the needs of a particular module.
302-
303-
Modules under the names `Plutus`, `Ledger` and `Plutus.V1.Ledger` SHOULD be imported qualified with their module name, as per the general module standards. An exception to this is `Plutus.V1.Ledger.Api`, where the `Ledger` name is preferred.
309+
In addition to the general module import rules, we follow some conventions
310+
on how we import the Plutus API modules, allowing for some flexibility
311+
depending on the needs of a particular module.
304312

305-
Some other exceptions to this are allowed where it may be more convenient to avoid longer qualified names.
313+
Modules under the names `Plutus`, `Ledger` and `Plutus.V1.Ledger` SHOULD
314+
be imported qualified with their module name, as per the general module standards.
315+
An exception to this is `Plutus.V1.Ledger.Api`, where the `Ledger` name is preferred.
306316

317+
Some other exceptions to this are allowed where it may be more convenient to
318+
avoid longer qualified names.
307319

308320
For example:
309321

@@ -321,11 +333,11 @@ In some cases it may be justified to use a shortened module name:
321333
import Plutus.V1.Ledger.AddressMap qualified as AddrMap
322334
```
323335

324-
Modules under `PlutusTx` that are extensions to `PlutusTx.Prelude` MAY be imported unqualified when it is reasonable to do so.
336+
Modules under `PlutusTx` that are extensions to `PlutusTx.Prelude` MAY be
337+
imported unqualified when it is reasonable to do so.
325338

326-
The `Plutus.V1.Ledger.Api` module SHOULD be avoided in favour of more specific modules where possible.
327-
328-
For example, we should avoid:
339+
The `Plutus.V1.Ledger.Api` module SHOULD be avoided in favour of more
340+
specific modules where possible. For example, we should avoid:
329341

330342
```haskell
331343
import Plutus.V1.Ledger.Api qualified as Ledger (ValidatorHash)
@@ -339,10 +351,9 @@ import Plutus.V1.Ledger.Scripts qualified as Scripts (ValidatorHash)
339351

340352
### Justification
341353

342-
The Plutus API modules can be confusing, with numerous modules involved, many exporting the same items.
343-
344-
Consistent qualified names help ease this problem, and decrease ambiguity about where imported items come from.
345-
354+
The Plutus API modules can be confusing, with numerous modules involved, many
355+
exporting the same items. Consistent qualified names help ease this problem,
356+
and decrease ambiguity about where imported items come from.
346357

347358
## LANGUAGE pragmata
348359

@@ -610,7 +621,7 @@ anyway. The only reason to derive either of these is for compatibility with
610621
legacy libraries, which we don't have any of, and the number of which shrinks
611622
every year. If we're using this extension at all, it's probably a mistake.
612623

613-
``Foldable`` is possibly the most widely-used, lawless type class. Its only laws
624+
``Foldable`` is possibly the most widely-used lawless type class. Its only laws
614625
are about self-consistency (such as agreement between ``foldMap`` and
615626
``foldr``), but unlike something like ``Functor``, ``Foldable`` doesn't have any
616627
laws specifying its behaviour outside of 'it compiles'. As a result, even if we
@@ -820,6 +831,8 @@ data Foo (a :: Type) = Bar | Baz [a]
820831
quux :: forall (m :: Type) . (Monoid m) => [m] -> m -> m
821832
```
822833

834+
`where`-bindings MUST have type signatures.
835+
823836
### Justification
824837

825838
Haskell lists are a large example of the legacy of the language: they (in the
@@ -833,7 +846,8 @@ fusion optimizations), from the point of view of field values, they are a poor
833846
choice from both an efficiency perspective, both in theory _and_ in practice.
834847
For almost all cases where you would want a list field value, a ``Vector`` field
835848
value is more appropriate, and in almost all others, some other structure (such
836-
as a ``Map``) is even better.
849+
as a ``Map``) is even better. We make a named exception for on-chain code, as no
850+
alternatives presently exist.
837851

838852
Partial functions are runtime bombs waiting to explode. The number of times the
839853
'impossible' happened, especially in production code, is significant in our
@@ -897,6 +911,24 @@ as well as ensuring that we don't make any errors ourselves. This, together with
897911
explicit foralls, essentially bring the same practices to the kind level as the
898912
Haskell community already considers to be good at the type level.
899913

914+
`where` bindings are quite common in idiomatic Haskell, and quite often contain
915+
non-trivial logic. They're also a common refactoring, and 'hole-driven
916+
development' tool, where you create a hole to be filled with a `where`-bound
917+
definition. Even in these cases, having an explicit signature on
918+
`where`-bindings helps: during development, you can use typed holes inside the
919+
`where`-binding with useful information (absent a signature, you'll get
920+
nothing), and it makes the code much easier to understand, especially if the
921+
`where`-binding is complex. It's also advantageous when 'promoting'
922+
`where`-binds to full top-level definitions, as the signature is already there.
923+
Since we need to do considerable type-level programming as part of Plutus, this
924+
becomes even more important, as GHC's type inference algorithm can often fail in
925+
those cases on `where`-bindings, which will sometimes fail to derive, giving a
926+
very strange error message, which would need a signature to solve anyway. By
927+
making this practice proactive, we are decreasing confusion, as well as
928+
increasing readability. While in theory, this standard should extend to
929+
`let`-bindings as well, these are much rarer, and can be given signatures with
930+
`::` if `ScopedTypeVariables` is on (which it is for us by default) if needed.
931+
900932
# Design practices
901933

902934
## Parse, don't validate

0 commit comments

Comments
 (0)