Safe Haskell | Safe-Inferred |
---|
Functions to help define call signatures.
This module, along with the Typecheck.Typecheck
class, define a little
DSL to express function signatures. Check existing calls for examples.
Argument passing, in an effort to be flexible, got a bit complicated. Each
Arg
has a name and a possible default. So right off there are three ways
to provide an argument:
- Pass it explicitly.
- If it is omitted, or
_
is passed explicitly, it will be sought in the dynamic environ, under the name<call_name>-<arg_name>
. E.g. given a callgenerator "name" $ \args -> call (required "arg1") ...
thenname-arg1 = 42 | call _
will get 42. Note that it uses the call name, and not the symbol it happens to bound to in this scope. This is because, while you may bind different kinds of trills totr
depending on the needs of the score, the two kinds of trills may have different arguments with different meanings. - If it's omitted, and not in the dynamic environ, the default will be used, provided there is one.
In addition, an arg may be a DeriveT.VPControlRef
or
DeriveT.ControlRef
, which introduces yet another way to provide the
value. An argument required_control "c"
will pass
a DeriveT.Ref
. Technically it's then up to the call to
decide what to do with it, but it will likely look it up at its chosen
point in time, which means you can provide the value by providing a c
control track or binding it explicitly e.g. %c = .5 | call
.
TODO: out of date, there is no longer Typecheck ControlRef, they are
resolved by Typecheck.from_val
- To further complicate the matter, the control arg may itself have a
default, to relieve the caller from always having to provide that control.
So an argument
control "c" 0.5
or an explicitly provided control valcall %c,.5
will default to 0.5 if thec
control is not in scope.
Since the arg defaulting and control defaulting are orthogonal, they can be combined:
- Pass it explicitly with a default:
call %c,.5
. This is either the value of%c
or 0.5. - Pass it via the dynamic environ:
call-arg1 = %c,.5 | call
. This is the same as the above, only the argument is provided implicitly. - Fall back on the built-in default:
control "c" 0.5
and then justcall
.
I originally envisioned the dynamic environ passing scheme to be a way to default certain arguments within the context of a track, to be used in a relatively ad-hoc way in specific parts of the score (e.g. all trills within this section of melody default to minor thirds), is not limited to numeric types, and is constant in time. A control, however, is intended to capture musical parameters that change in time over the course of the piece, and is numeric or a pitch. So while dynamic environ args are forced to be specific to a certain call by prepending the call's name, control names should generally have more general and abstract names.
On the subject of controls, controls (and numeric vals in general) have
another layer of complexity since they carry types. For example, here's
a gloriously complicated argument: defaulted "speed" (typed_control
"tremolo-speed" 10 ScoreT.Real)
. This argument defaults to
%tremolo-speed,10s
. If it's not given, it will have the value 10s
. If
the %tremolo-speed
control is in scope but untyped, its values will be
interpreted as RealTime. If it's in scope and typed (e.g. with
a tremolo-speed:t
track), then its values will be interpreted as
ScoreTime.
Another wrinkle in argument passing is that, in addition to being
required
, which has no default, or being defaulted
, which has
a default, they can be defaulted
with a default of Nothing. This passes
the argument as a Maybe a
instead of a
and lets the call distinguish
whether an argument was provided or not. This is for arguments which are
defaulted but need a more complicated defaulting strategy than simply
a constant.
Synopsis
- data Parser a
- type Generator y d = PassedArgs y -> Deriver d
- type Transformer y d = PassedArgs y -> Deriver d -> Deriver d
- data Arg
- check :: (a -> Maybe Text) -> Parser a -> Parser a
- parse_or_throw :: Taggable d => Parser a -> PassedArgs d -> Deriver a
- require_right :: Either Error a -> Deriver a
- parse :: Taggable d => Parser a -> PassedArgs d -> Deriver (Either Error a)
- parse_vals :: Parser a -> Context Tagged -> CallName -> [DeriveT.Val] -> Deriver (Either Error a)
- data Dummy
- no_args :: Parser ()
- required :: forall a. Typecheck.Typecheck a => ArgName -> Doc.Doc -> Parser a
- required_env :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> Doc.Doc -> Parser a
- defaulted :: forall a deflt. (Typecheck.Typecheck a, Typecheck.ToVal deflt) => ArgName -> deflt -> Doc.Doc -> Parser a
- defaulted_env :: forall a deflt. (Typecheck.Typecheck a, Typecheck.ToVal deflt) => ArgName -> EnvironDefault -> deflt -> Doc.Doc -> Parser a
- defaulted_env_quoted :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> DeriveT.Quoted -> Doc.Doc -> Parser a
- maybe_defaulted :: (Typecheck.Typecheck a, Typecheck.ToVal deflt) => ArgName -> Maybe deflt -> Doc.Doc -> Parser a
- environ :: forall a deflt. (Typecheck.Typecheck a, Typecheck.ToVal deflt) => ArgName -> EnvironDefault -> deflt -> Doc.Doc -> Parser a
- environ_key :: (Typecheck.Typecheck a, Typecheck.ToVal deflt) => Key -> deflt -> Doc.Doc -> Parser a
- environ_quoted :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> DeriveT.Quoted -> Doc.Doc -> Parser a
- required_environ :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> Doc.Doc -> Parser a
- required_environ_key :: Typecheck.Typecheck a => Key -> Doc.Doc -> Parser a
- optional :: forall a. (Typecheck.Typecheck a, ShowVal.ShowVal a) => ArgName -> a -> Doc.Doc -> Parser a
- optional_env :: forall a. (Typecheck.Typecheck a, ShowVal.ShowVal a) => ArgName -> EnvironDefault -> a -> Doc.Doc -> Parser a
- many :: forall a. Typecheck.Typecheck a => ArgName -> Doc.Doc -> Parser [a]
- many_vals :: ArgName -> Doc.Doc -> Parser [DeriveT.Val]
- many1 :: forall a. Typecheck.Typecheck a => ArgName -> Doc.Doc -> Parser (NonEmpty a)
- many_pairs :: forall a b. (Typecheck.Typecheck a, Typecheck.Typecheck b) => ArgName -> Doc.Doc -> Parser [(a, b)]
- many1_pairs :: forall a b. (Typecheck.Typecheck a, Typecheck.Typecheck b) => ArgName -> Doc.Doc -> Parser (NonEmpty (a, b))
- required_vals :: [ArgDoc] -> Parser [Arg]
- data EnvironDefault
- = None
- | Prefixed
- | Unprefixed
- | Both
- prefixed_environ :: CallName -> ArgName -> Key
- environ_keys :: CallName -> ArgName -> EnvironDefault -> [Key]
- call :: Taggable y => Parser a -> (a -> Generator y d) -> WithArgDoc (Generator y d)
- call_sub :: Taggable y => Parser a -> (a -> Generator y d) -> WithArgDoc (Generator y d)
- call0 :: Taggable y => Generator y d -> WithArgDoc (Generator y d)
- callt :: Taggable y => Parser a -> (a -> Transformer y d) -> WithArgDoc (Transformer y d)
- call0t :: Taggable y => Transformer y d -> WithArgDoc (Transformer y d)
Documentation
type Generator y d = PassedArgs y -> Deriver d Source #
Similar to GeneratorF
, but leaves the PassedArgs prev val
type free. This is important for val calls, which use Tagged.
type Transformer y d = PassedArgs y -> Deriver d -> Deriver d Source #
Annotate a parser with a check on its value.
parse_or_throw :: Taggable d => Parser a -> PassedArgs d -> Deriver a Source #
require_right :: Either Error a -> Deriver a Source #
parse :: Taggable d => Parser a -> PassedArgs d -> Deriver (Either Error a) Source #
Run a parser against the current derive state.
parse_vals :: Parser a -> Context Tagged -> CallName -> [DeriveT.Val] -> Deriver (Either Error a) Source #
Now that the default can be any ToVal and may be a different type than the parser, it can get ambiguous, especially if it's a Nothing or []. Since all that matters is (show_val . to_val), and show_val of Nothing or [] is always _ or (list), the type doesn't matter. I could use Int, but I'll use this to explicitly mark that it doesn't matter.
Instances
Typecheck.ToVal Dummy Source # | |
Defined in Derive.Sig to_val :: Dummy -> DeriveT.Val Source # |
parsers
required :: forall a. Typecheck.Typecheck a => ArgName -> Doc.Doc -> Parser a Source #
The argument is required to be present, and have the right type.
required_env :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> Doc.Doc -> Parser a Source #
defaulted :: forall a deflt. (Typecheck.Typecheck a, Typecheck.ToVal deflt) => ArgName -> deflt -> Doc.Doc -> Parser a Source #
The argument is not required to be present, but if it is, it has to have either the right type or be VNotGiven.
defaulted_env :: forall a deflt. (Typecheck.Typecheck a, Typecheck.ToVal deflt) => ArgName -> EnvironDefault -> deflt -> Doc.Doc -> Parser a Source #
defaulted_env_quoted :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> DeriveT.Quoted -> Doc.Doc -> Parser a Source #
The defaulted value can be a DeriveT.Quoted
, which will be evaluated
if needed.
maybe_defaulted :: (Typecheck.Typecheck a, Typecheck.ToVal deflt) => ArgName -> Maybe deflt -> Doc.Doc -> Parser a Source #
:: forall a deflt. (Typecheck.Typecheck a, Typecheck.ToVal deflt) | |
=> ArgName | |
-> EnvironDefault | None doesn't make any sense, but, well, don't pass that then. |
-> deflt | |
-> Doc.Doc | |
-> Parser a |
This is an argument which is not actually parsed from the argument list.
Instead it's looked up it the environ according to the normal defaulting
rules. So it's like defaulted
except there is no positional argument.
Of course, the call could just look in the environ itself, but this way it's uniform and automatically documented.
environ_key :: (Typecheck.Typecheck a, Typecheck.ToVal deflt) => Key -> deflt -> Doc.Doc -> Parser a Source #
A shortcut for an unprefixed environ key.
environ_quoted :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> DeriveT.Quoted -> Doc.Doc -> Parser a Source #
This is like environ
, but the default is a DeriveT.Quoted
, which
will be evaluated if needed.
required_environ :: forall a. Typecheck.Typecheck a => ArgName -> EnvironDefault -> Doc.Doc -> Parser a Source #
This is like environ
, but without a default.
required_environ_key :: Typecheck.Typecheck a => Key -> Doc.Doc -> Parser a Source #
optional :: forall a. (Typecheck.Typecheck a, ShowVal.ShowVal a) => ArgName -> a -> Doc.Doc -> Parser a Source #
optional_env :: forall a. (Typecheck.Typecheck a, ShowVal.ShowVal a) => ArgName -> EnvironDefault -> a -> Doc.Doc -> Parser a Source #
many :: forall a. Typecheck.Typecheck a => ArgName -> Doc.Doc -> Parser [a] Source #
Collect the rest of the arguments.
many_vals :: ArgName -> Doc.Doc -> Parser [DeriveT.Val] Source #
many
specialized to Vals, to avoid a type annotation.
many1 :: forall a. Typecheck.Typecheck a => ArgName -> Doc.Doc -> Parser (NonEmpty a) Source #
Collect the rest of the arguments, but there must be at least one.
many_pairs :: forall a b. (Typecheck.Typecheck a, Typecheck.Typecheck b) => ArgName -> Doc.Doc -> Parser [(a, b)] Source #
Collect the rest of the arguments, but expect a even number of them and pair them up.
many1_pairs :: forall a b. (Typecheck.Typecheck a, Typecheck.Typecheck b) => ArgName -> Doc.Doc -> Parser (NonEmpty (a, b)) Source #
Like many_pairs
, but require at least one pair.
required_vals :: [ArgDoc] -> Parser [Arg] Source #
Require one Val for each ArgDoc given, but otherwise do no typechecking.
defaults
data EnvironDefault Source #
This configures how an argument looks for a default in the environ.
None | Don't default from environ at all. |
Prefixed | Look for |
Unprefixed | Look for |
Both | First look for a prefixed key, then for an unprefixed one. |
Instances
Show EnvironDefault Source # | |
Defined in Derive.Deriver.Monad showsPrec :: Int -> EnvironDefault -> ShowS # show :: EnvironDefault -> String # showList :: [EnvironDefault] -> ShowS # | |
Eq EnvironDefault Source # | |
Defined in Derive.Deriver.Monad (==) :: EnvironDefault -> EnvironDefault -> Bool # (/=) :: EnvironDefault -> EnvironDefault -> Bool # | |
Ord EnvironDefault Source # | |
Defined in Derive.Deriver.Monad compare :: EnvironDefault -> EnvironDefault -> Ordering # (<) :: EnvironDefault -> EnvironDefault -> Bool # (<=) :: EnvironDefault -> EnvironDefault -> Bool # (>) :: EnvironDefault -> EnvironDefault -> Bool # (>=) :: EnvironDefault -> EnvironDefault -> Bool # max :: EnvironDefault -> EnvironDefault -> EnvironDefault # min :: EnvironDefault -> EnvironDefault -> EnvironDefault # | |
Pretty.Pretty EnvironDefault Source # | |
Defined in Derive.Deriver.Monad pretty :: EnvironDefault -> Text Source # format :: EnvironDefault -> Doc Source # formatList :: [EnvironDefault] -> Doc Source # |
environ_keys :: CallName -> ArgName -> EnvironDefault -> [Key] Source #
call
call0 :: Taggable y => Generator y d -> WithArgDoc (Generator y d) Source #
Specialization of call
for 0 arguments.
callt :: Taggable y => Parser a -> (a -> Transformer y d) -> WithArgDoc (Transformer y d) Source #
call0t :: Taggable y => Transformer y d -> WithArgDoc (Transformer y d) Source #
Specialization of callt
for 0 arguments.