Rename Maybe to Optional

The primary reason for this change is to make it easier to describe these values
both in documentation and in informal communication between developers.

Before, you'd have to say things like:

* A value of type `Maybe` (incorrect)
* A `Maybe` value (sounds weird)
* A value of type `Maybe a` for some `a` (correct, but very verbose)

Now you can say an `Optional` value and the meaning is precise and clear

A secondary reason for this change is to keep the terminology close to the
intended use of the language for configuration files.  Describing fields as
`Optional` instead of `Maybe` makes a lot of sense for configurations.

The disadvantage is that some uses of `Optional` don't make sense.  For example,
consider the type of `List/head`:

    List/head : ∀(a : Type) → List a → Optional a

It seems weird to say that the result of `List/head` is `Optional`.  However,
many languages (such as Java/Scala/F#/Swift) already use this name or `Option` and
they get along just fine.
This commit is contained in:
Gabriel Gonzalez 2016-11-12 08:31:13 -08:00
parent 091b4cb36b
commit 7fe24bc8c4
4 changed files with 87 additions and 101 deletions

View File

@ -485,11 +485,11 @@ Nothing
maybe :: Type a -> Type (Maybe a)
maybe (Type extractIn expectedIn) = Type extractOut expectedOut
where
extractOut (MaybeLit _ es) = traverse extractIn es'
extractOut (OptionalLit _ es) = traverse extractIn es'
where
es' = if Data.Vector.null es then Nothing else Just (Data.Vector.head es)
expectedOut = App Maybe expectedIn
expectedOut = App Optional expectedIn
{-| Decode a `Vector`

View File

@ -240,13 +240,13 @@ data Expr s a
| ListIndexed
-- | > ListReverse ~ List/reverse
| ListReverse
-- | > Maybe ~ Maybe
| Maybe
-- | > MaybeLit t [e] ~ [e] : Maybe t
-- > MaybeLit t [] ~ [] : Maybe t
| MaybeLit (Expr s a) (Vector (Expr s a))
-- | > MaybeFold ~ Maybe/fold
| MaybeFold
-- | > Optional ~ Optional
| Optional
-- | > OptionalLit t [e] ~ [e] : Optional t
-- > OptionalLit t [] ~ [] : Optional t
| OptionalLit (Expr s a) (Vector (Expr s a))
-- | > OptionalFold ~ Optional/fold
| OptionalFold
-- | > Record [(k1, t1), (k2, t2)] ~ { k1 : t1, k2 : t1 }
| Record (Map Text (Expr s a))
-- | > RecordLit [(k1, v1), (k2, v2)] ~ { k1 = v1, k2 = v2 }
@ -314,9 +314,9 @@ instance Monad (Expr s) where
ListLast >>= _ = ListLast
ListIndexed >>= _ = ListIndexed
ListReverse >>= _ = ListReverse
Maybe >>= _ = Maybe
MaybeLit t es >>= k = MaybeLit (t >>= k) (fmap (>>= k) es)
MaybeFold >>= _ = MaybeFold
Optional >>= _ = Optional
OptionalLit t es >>= k = OptionalLit (t >>= k) (fmap (>>= k) es)
OptionalFold >>= _ = OptionalFold
Record kts >>= k = Record (fmap (>>= k) kts)
RecordLit kvs >>= k = RecordLit (fmap (>>= k) kvs)
Union kts >>= k = Union (fmap (>>= k) kts)
@ -367,9 +367,9 @@ instance Bifunctor Expr where
first _ ListLast = ListLast
first _ ListIndexed = ListIndexed
first _ ListReverse = ListReverse
first _ Maybe = Maybe
first k (MaybeLit a b ) = MaybeLit (first k a) (fmap (first k) b)
first _ MaybeFold = MaybeFold
first _ Optional = Optional
first k (OptionalLit a b ) = OptionalLit (first k a) (fmap (first k) b)
first _ OptionalFold = OptionalFold
first k (Record a ) = Record (fmap (first k) a)
first k (RecordLit a ) = RecordLit (fmap (first k) a)
first k (Union a ) = Union (fmap (first k) a)
@ -471,24 +471,10 @@ buildExpr1 (Let a (Just b) c d) =
<> buildExpr0 c
<> " in "
<> buildExpr1 d
-- Note: The corresponding @Expr1@ parser in "Dhall.Parser" deviates from the
-- following two cases due to the fact that the @alex@-generated parser does not
-- not backtrack perfectly. The exact translation would be:
--
-- > Expr1
-- > ...
-- > | '[' Elems ']' : 'List' Expr6
-- > { ListLit $6 (Data.Vector.fromList $2) }
-- > | '[' Elems ']' : 'Maybe' Expr6
-- > { MaybeLit $6 (Data.Vector.fromList $2) }
--
-- ... but that fails to parse @Maybe@ literals correctly, so I worked around
-- it by changing the parser to an equivalent parser but keeping the
-- builder the same.
buildExpr1 (ListLit a b) =
"[" <> buildElems (Data.Vector.toList b) <> "] : List " <> buildExpr6 a
buildExpr1 (MaybeLit a b) =
"[" <> buildElems (Data.Vector.toList b) <> "] : Maybe " <> buildExpr6 a
buildExpr1 (OptionalLit a b) =
"[" <> buildElems (Data.Vector.toList b) <> "] : Optional " <> buildExpr6 a
buildExpr1 (Merge a b c) =
"apply " <> buildExpr6 a <> " " <> buildExpr6 b <> " : " <> buildExpr5 c
buildExpr1 (Note _ b) =
@ -567,10 +553,10 @@ buildExpr6 ListIndexed =
"List/indexed"
buildExpr6 ListReverse =
"List/reverse"
buildExpr6 Maybe =
"Maybe"
buildExpr6 MaybeFold =
"Maybe/fold"
buildExpr6 Optional =
"Optional"
buildExpr6 OptionalFold =
"Optional/fold"
buildExpr6 (BoolLit True) =
"True"
buildExpr6 (BoolLit False) =
@ -847,12 +833,12 @@ shift _ _ ListHead = ListHead
shift _ _ ListLast = ListLast
shift _ _ ListIndexed = ListIndexed
shift _ _ ListReverse = ListReverse
shift _ _ Maybe = Maybe
shift d v (MaybeLit a b) = MaybeLit a' b'
shift _ _ Optional = Optional
shift d v (OptionalLit a b) = OptionalLit a' b'
where
a' = shift d v a
b' = fmap (shift d v) b
shift _ _ MaybeFold = MaybeFold
shift _ _ OptionalFold = OptionalFold
shift d v (Record a) = Record a'
where
a' = fmap (shift d v) a
@ -978,12 +964,12 @@ subst _ _ ListHead = ListHead
subst _ _ ListLast = ListLast
subst _ _ ListIndexed = ListIndexed
subst _ _ ListReverse = ListReverse
subst _ _ Maybe = Maybe
subst x e (MaybeLit a b) = MaybeLit a' b'
subst _ _ Optional = Optional
subst x e (OptionalLit a b) = OptionalLit a' b'
where
a' = subst x e a
b' = fmap (subst x e) b
subst _ _ MaybeFold = MaybeFold
subst _ _ OptionalFold = OptionalFold
subst x e (Record kts) = Record (fmap (subst x e) kts)
subst x e (RecordLit kvs) = RecordLit (fmap (subst x e) kvs)
subst x e (Union kts) = Union (fmap (subst x e) kts)
@ -1092,9 +1078,9 @@ normalize e = case e of
App (App ListLength _) (ListLit _ ys) ->
NaturalLit (fromIntegral (Data.Vector.length ys))
App (App ListHead _) (ListLit t ys) ->
normalize (MaybeLit t (Data.Vector.take 1 ys))
normalize (OptionalLit t (Data.Vector.take 1 ys))
App (App ListLast _) (ListLit t ys) ->
normalize (MaybeLit t y)
normalize (OptionalLit t y)
where
y = if Data.Vector.null ys
then Data.Vector.empty
@ -1114,7 +1100,7 @@ normalize e = case e of
]
App (App ListReverse _) (ListLit t xs) ->
normalize (ListLit t (Data.Vector.reverse xs))
App (App (App (App (App MaybeFold _) (MaybeLit _ xs)) _) just) nothing ->
App (App (App (App (App OptionalFold _) (OptionalLit _ xs)) _) just) nothing ->
normalize (maybe nothing just' (toMaybe xs))
where
just' y = App just y
@ -1232,12 +1218,12 @@ normalize e = case e of
ListLast -> ListLast
ListIndexed -> ListIndexed
ListReverse -> ListReverse
Maybe -> Maybe
MaybeLit t es -> MaybeLit t' es'
Optional -> Optional
OptionalLit t es -> OptionalLit t' es'
where
t' = normalize t
es' = fmap normalize es
MaybeFold -> MaybeFold
OptionalFold -> OptionalFold
Record kts -> Record kts'
where
kts' = fmap normalize kts

View File

@ -138,8 +138,8 @@ identifierStyle = IdentifierStyle
, "List/last"
, "List/indexed"
, "List/reverse"
, "Maybe"
, "Maybe/fold"
, "Optional"
, "Optional/fold"
]
, _styleHighlight = Identifier
, _styleReservedHighlight = ReservedIdentifier
@ -280,8 +280,8 @@ listLike =
return ListLit
listLike1 = do
reserve "Maybe"
return MaybeLit
reserve "Optional"
return OptionalLit
-- TODO: Add `noted` in the right places here
exprC :: Parser (Expr Src Path)
@ -451,12 +451,12 @@ exprF = choice
return ListReverse
exprF19 = do
reserve "Maybe"
return Maybe
reserve "Optional"
return Optional
exprF20 = do
reserve "Maybe/fold"
return MaybeFold
reserve "Optional/fold"
return OptionalFold
exprF21 = do
reserve "Bool"

View File

@ -90,7 +90,7 @@ propEqual eL0 eR0 =
go Double Double = return True
go Text Text = return True
go List List = return True
go Maybe Maybe = return True
go Optional Optional = return True
go (Record ktsL0) (Record ktsR0) = do
let loop ((kL, tL):ktsL) ((kR, tR):ktsR)
| kL == kR = do
@ -359,9 +359,9 @@ typeWith _ ListFold = do
typeWith _ ListLength = do
return (Pi "a" (Const Type) (Pi "_" (App List "a") Natural))
typeWith _ ListHead = do
return (Pi "a" (Const Type) (Pi "_" (App List "a") (App Maybe "a")))
return (Pi "a" (Const Type) (Pi "_" (App List "a") (App Optional "a")))
typeWith _ ListLast = do
return (Pi "a" (Const Type) (Pi "_" (App List "a") (App Maybe "a")))
return (Pi "a" (Const Type) (Pi "_" (App List "a") (App Optional "a")))
typeWith _ ListIndexed = do
let kts = [("index", Natural), ("value", "a")]
return
@ -370,16 +370,16 @@ typeWith _ ListIndexed = do
(App List (Record (Data.Map.fromList kts))) ) )
typeWith _ ListReverse = do
return (Pi "a" (Const Type) (Pi "_" (App List "a") (App List "a")))
typeWith _ Maybe = do
typeWith _ Optional = do
return (Pi "_" (Const Type) (Const Type))
typeWith ctx e@(MaybeLit t xs ) = do
typeWith ctx e@(OptionalLit t xs) = do
s <- fmap Dhall.Core.normalize (typeWith ctx t)
case s of
Const Type -> return ()
_ -> Left (TypeError ctx e (InvalidMaybeType t))
_ -> Left (TypeError ctx e (InvalidOptionalType t))
let n = Data.Vector.length xs
if 2 <= n
then Left (TypeError ctx e (InvalidMaybeLiteral n))
then Left (TypeError ctx e (InvalidOptionalLiteral n))
else return ()
forM_ xs (\x -> do
t' <- typeWith ctx x
@ -388,12 +388,12 @@ typeWith ctx e@(MaybeLit t xs ) = do
else do
let nf_t = Dhall.Core.normalize t
let nf_t' = Dhall.Core.normalize t'
Left (TypeError ctx e (InvalidMaybeElement x nf_t nf_t')) )
return (App Maybe t)
typeWith _ MaybeFold = do
Left (TypeError ctx e (InvalidOptionalElement x nf_t nf_t')) )
return (App Optional t)
typeWith _ OptionalFold = do
return
(Pi "a" (Const Type)
(Pi "_" (App Maybe "a")
(Pi "_" (App Optional "a")
(Pi "maybe" (Const Type)
(Pi "just" (Pi "_" "a" "maybe")
(Pi "nothing" "maybe" "maybe") ) ) ) )
@ -520,9 +520,9 @@ data TypeMessage s
| Untyped
| InvalidListElement Int (Expr s X) (Expr s X) (Expr s X)
| InvalidListType (Expr s X)
| InvalidMaybeElement (Expr s X) (Expr s X) (Expr s X)
| InvalidMaybeLiteral Int
| InvalidMaybeType (Expr s X)
| InvalidOptionalElement (Expr s X) (Expr s X) (Expr s X)
| InvalidOptionalLiteral Int
| InvalidOptionalType (Expr s X)
| InvalidPredicate (Expr s X) (Expr s X)
| IfBranchMismatch (Expr s X) (Expr s X) (Expr s X) (Expr s X)
| IfBranchMustBeTerm Bool (Expr s X) (Expr s X) (Expr s X)
@ -890,22 +890,22 @@ the following expressions are all functions because they have a function type:
The function's output kind is Type
The function's input kind is Type
Function's input has kind Type
List/head : (a : Type) (List a Maybe a) A function can return
another function
List/head : (a : Type) (List a Optional a) A function can return
another function
The function's output type is List a Maybe a
Function's output has type List a Optional a
The function's input type is List Text
List/head Text : List Text Maybe Text A function applied to an
argument can be a function
List/head Text : List Text Optional Text A function applied to an
argument can be a function
The function's output type is Maybe Text
The function's output type is Optional Text
An expression is not a function if the expression's type is not of the form
@ -1529,40 +1529,40 @@ Your list elements should have this type:
txt2 = Text.toStrict (Dhall.Core.pretty expr1)
txt3 = Text.toStrict (Dhall.Core.pretty expr2)
prettyTypeMessage (InvalidMaybeType expr0) = ErrorMessages {..}
prettyTypeMessage (InvalidOptionalType expr0) = ErrorMessages {..}
where
short = "Invalid type for Maybe elements"
short = "Invalid type for Optional elements"
long =
Builder.fromText [NeatInterpolation.text|
Explanation: Every optional value ends with a type annotation for the element
that might be stored inside. For example, these are valid expressions:
[1] : Maybe Integer -- An optional value that's present
[] : Maybe Integer -- An optional value that's absent
[1] : Optional Integer -- An optional value that's present
[] : Optional Integer -- An optional value that's absent
The type following the `Maybe` is the "type parameter", and must be a type:
The type following the `Optional` is the "type parameter", and must be a type:
Maybe Integer -- This is valid, because `Integer` is a type
Maybe Text -- This is also valid, because `Text` is a type
Optional Integer -- This is valid, because `Integer` is a type
Optional Text -- This is also valid, because `Text` is a type
... but the type parameter must *not* be a term or kind:
Maybe 1 -- This is invalid, because `1` is a term
Maybe Type -- This is invalid, because `Type` is a kind
Optional 1 -- This is invalid, because `1` is a term
Optional Type -- This is invalid, because `Type` is a kind
You provided a type parameter for the `Maybe` that is not a valid type:
You provided a type parameter for the `Optional` that is not a valid type:
$insert
|]
where
txt0 = Text.toStrict (Builder.toLazyText (Dhall.Core.buildExpr6 expr0))
insert = indent [NeatInterpolation.text|
[ ... ] : Maybe $txt0
[ ... ] : Optional $txt0
-- ^ This needs to be a type
|]
prettyTypeMessage (InvalidMaybeElement expr0 expr1 expr2) = ErrorMessages {..}
prettyTypeMessage (InvalidOptionalElement expr0 expr1 expr2) = ErrorMessages {..}
where
short = "Optional expression with an element of the wrong type"
@ -1571,11 +1571,11 @@ prettyTypeMessage (InvalidMaybeElement expr0 expr1 expr2) = ErrorMessages {..}
Explanation: An optional value that is present must have a type matching the
corresponding type annotation. For example, this is a valid optional value:
[1] : Maybe Integer -- The type of `1` is `Integer`, which matches
[1] : Optional Integer -- The type of `1` is `Integer`, which matches
... but this is *not* a valid optional value:
[1] : Maybe Text -- Invalid, because the type of `1` is not `Text`
[1] : Optional Text -- Invalid, because the type of `1` is not `Text`
Your optional value has a type which does not match the type annotation:
@ -1591,11 +1591,11 @@ The element you provided actually has this type:
insert = indent [NeatInterpolation.text|
[ $txt0
-- ^ This value ...
] : Maybe $txt1
-- ^ ... needs to have a type matching this type parameter
] : Optional $txt1
-- ^ ... needs to have a type matching this type parameter
|]
prettyTypeMessage (InvalidMaybeLiteral n) = ErrorMessages {..}
prettyTypeMessage (InvalidOptionalLiteral n) = ErrorMessages {..}
where
short = "More than one element for an optional value"
@ -1604,16 +1604,16 @@ prettyTypeMessage (InvalidMaybeLiteral n) = ErrorMessages {..}
Explanation: The syntax for an optional value resembles the syntax for `List`
literals:
[] : Maybe Integer -- A valid literal for an absent optional value
[1] : Maybe Integer -- A valid literal for a present optional value
[] : List Integer -- A valid literal for an empty (0-element) `List`
[1] : List Integer -- A valid literal for a singleton (1-element) `List`
[] : Optional Integer -- A valid literal for an absent optional value
[1] : Optional Integer -- A valid literal for a present optional value
[] : List Integer -- A valid literal for an empty (0-element) `List`
[1] : List Integer -- A valid literal for a singleton (1-element) `List`
However, an optional value can *not* have more than one element, whereas a
`List` can have multiple elements:
[1, 2] : Maybe Integer -- Invalid: multiple elements not allowed
[1, 2] : List Integer -- Valid : multiple elements allowed
[1, 2] : Optional Integer -- Invalid: multiple elements not allowed
[1, 2] : List Integer -- Valid : multiple elements allowed
Your optional value had $txt0 elements, which is not allowed. Optional values
can only have at most one element