View Source Croma.Defun (croma v0.11.3)
Module that provides Croma.Defun.defun/2
macro.
Link to this section Summary
Functions
Defines a function together with its typespec.
Defines a private function together with its typespec.
Defines a unit-testable private function together with its typespec.
Link to this section Functions
Defines a function together with its typespec.
This provides a lighter-weight syntax for functions with type specifications and functions with multiple clauses.
example
Example
The following examples assume that Croma.Defun
is imported
(you can import it by use Croma
).
defun f(a :: integer, b :: String.t) :: String.t do
"#{a} #{b}"
end
The code above is expanded to the following function definition.
@spec f(integer, String.t) :: String.t
def f(a, b) do
"#{a} #{b}"
end
Function with multiple clauses and/or pattern matching on parameters can be defined
in the same way as case do ... end
:
defun dumbmap(as :: [a], f :: (a -> b)) :: [b] when a: term, b: term do
([] , _) -> []
([h | t], f) -> [f.(h) | dumbmap(t, f)]
end
is converted to
@spec dumbmap([a], (a -> b)) :: [b] when a: term, b: term
def dumbmap(as, f)
def dumbmap([], _) do
[]
end
def dumbmap([h | t], f) do
[f.(h) | dumbmap(t, f)]
end
pattern-matching-on-function-parameter-and-omitting-parameter-s-type
Pattern matching on function parameter and omitting parameter's type
If you omit parameter's type, its type is infered from the parameter's expression. Suppose we have the following function:
defun f(%MyStruct{field1: field1, field2: field2}) :: String.t do
"#{field1} #{field2}"
end
then the parameter type becomes MyStruct.t
.
@spec f(MyStruct.t) :: String.t
def f(a1)
def f(%MyStruct{field1: field1, field2: field2}) do
"#{field1} #{field2}"
end
generating-guards-from-argument-types
Generating guards from argument types
Simple guard expressions can be generated by defun/2
using g[type]
syntax.
For example,
defun f(s :: g[String.t], i :: g[integer]) :: String.t do
"#{s} #{i}"
end
is converted to the following function with when is_integer(i)
guard.
@spec f(String.t, integer) :: String.t
def f(s, i)
def f(s, i) when is_binary(s) and is_integer(i) do
"#{s} #{i}"
end
For supported types of guard-generation please refer to the source code of Croma.Guard.make/3
.
Guard generation can be disabled by setting application config at compile time.
For example, by putting the following into config/config.exs
,
config :croma, [
defun_generate_guard: false
]
then g[String.t]
becomes semantically the same as String.t
.
validating-arguments-and-return-value-based-on-their-types
Validating arguments and return value based on their types
You can instrument check of pre/post conditions by specifying type as v[type]
.
For instance,
defmodule MyString do
use Croma.SubtypeOfString, pattern: ~r/^foo|bar$/
end
defun f(s :: v[MyString.t]) :: atom do
String.to_atom(s)
end
becomes the following function definition that calls valid?/1
at the top of its body:
@spec f(MyString.t) :: atom
def f(s)
def f(s) do
if !MyString.valid?(s) do
raise "..."
end
String.to_atom(s)
end
The generated code assumes that valid?/1
function is defined in the type module of the specified type.
For primitive types croma defines their type modules and thus you can freely use e.g. v[integer]
.
Generating validation of arguments and return values can be disabled by setting application config during compilation.
config :croma, [
defun_generate_validation: false
]
known-limitations
Known limitations
- Overloaded typespecs are not supported.
- Guard generation and validation are not allowed to be used with multi-clause syntax.
- Using unquote fragment in parameter list is not fully supported.
try
block is not implicitly started in body ofdefun
, in contrast todef
.
Defines a private function together with its typespec.
See defun/2
for usage of this macro.
Defines a unit-testable private function together with its typespec.
See defun/2
for usage of this macro.
See also Croma.Defpt.defpt/2
.