croma v0.3.8 Croma.Defun
Module that provides Croma.Defun.defun/2
macro.
Summary
Macros
Defines a function together with its typespec. This provides a lighter-weight syntax for functions with type specifications and functions with multiple clauses
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
Macros
Defines a function together with its typespec. This provides a lighter-weight syntax for functions with type specifications and functions with multiple clauses.
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
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
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
.
Validating arguments based on their types
You can instrument check of preconditions on arguments by specifying argument’s 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 validate/1
at the top of its body:
@spec f(MyString.t) :: atom
def f(s)
def f(s) do
s = case MyString.validate(s) do
{:ok , value } -> value
{:error, reason} -> raise "..."
end
String.to_atom(s)
end
The generated code assumes that validate/1
function is defined in the same module as the specified type.
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.
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
.