For a jumpstart to, for example, Typing Functions.
Create a new project
$ mix new cards
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/cards.ex
* creating test
* creating test/test_helper.exs
* creating test/cards_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd cards
mix test
Run "mix help" for more commands.
$ cd cards
$
In mix.exs
change:
defp deps do
[
{:dialyxir, "~> 0.5", only: [:dev], runtime: false}
]
end
and run
$ mix do deps.get, deps.compile
Running dependency resolution...
Dependency resolution completed:
dialyxir 0.5.1
* Getting dialyxir (Hex package)
Checking package (https://repo.hex.pm/tarballs/dialyxir-0.5.1.tar)
Using locally cached package
==> dialyxir
Compiling 5 files (.ex)
Generated dialyxir app
$
then
$ mix dialyzer
Compiling 1 file (.ex)
Generated cards app
Checking PLT...
[:compiler, :elixir, :kernel, :logger, :stdlib]
Finding suitable PLTs
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Looking up modules in dialyxir_erlang-20.2.2.plt
Finding applications for dialyxir_erlang-20.2.2.plt
Finding modules for dialyxir_erlang-20.2.2.plt
Checking 163 modules in dialyxir_erlang-20.2.2.plt
Finding applications for dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Finding modules for dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Copying dialyxir_erlang-20.2.2.plt to dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Checking 163 modules in dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Adding 228 modules to dialyxir_erlang-20.2.2_elixir-1.6.1.plt
Finding applications for dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Finding modules for dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Copying dialyxir_erlang-20.2.2_elixir-1.6.1.plt to dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Looking up modules in dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Checking 391 modules in dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Adding 58 modules to dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt
Starting Dialyzer
dialyzer args: [
check_plt: false,
init_plt: '/cards/_build/dev/dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt',
files_rec: ['/cards/_build/dev/lib/cards/ebin'],
warnings: [:unknown]
]
done in 0m0.87s
done (passed successfully)
$
Change the contents of cards/lib/cards.ex
to
# cards/lib/cards.ex
defmodule Cards do
@type suit() :: :spades | :clubs | :hearts | :diamonds
@type value() :: 1..10 | :j | :q | :k
@type card() :: {suit(), value()}
@spec kind(card()) :: :face | :number
def kind({_,a}) when a >= 1 and a <= 10,
do: :number
def kind(_),
do: :face
@spec main(list(binary())) :: :ok
def main(_argv) do
:number = kind({:spades, 7})
:face = kind({:spades, :k})
:number = kind({:rubies, 4}) # should be :diamonds, not :rubies
:face = kind({:clubs, :q})
:ok
end
end
Now run:
$ iex -S mix
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Compiling 1 file (.ex)
Interactive Elixir (1.6.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Cards.main([])
:ok
iex(2)>
BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded
(v)ersion (k)ill (D)b-tables (d)istribution
a
$ mix dialyzer
Checking PLT...
[:compiler, :elixir, :kernel, :logger, :stdlib]
PLT is up to date!
Starting Dialyzer
dialyzer args: [
check_plt: false,
init_plt: '/cards/_build/dev/dialyxir_erlang-20.2.2_elixir-1.6.1_deps-dev.plt',
files_rec: ['/cards/_build/dev/lib/cards/ebin'],
warnings: [:unknown]
]
done in 0m1.01s
lib/cards.ex:14: Function main/1 has no local return
lib/cards.ex:17: The call 'Elixir.Cards':kind({'rubies',4}) breaks the contract (card()) -> 'face' | 'number'
done (warnings were emitted)
$
See also Typespecs.
Alternately:
# lib/cards.ex
defmodule Cards do
@type suit() :: :spades | :clubs | :hearts | :diamonds
@type value() :: 1..10 | :j | :q | :k
@type card() :: {suit(), value()}
@spec kind(c) :: r when c: card(), r: :face | :number
def kind({_,a}) when a >= 1 and a <= 10,
do: :number
def kind(_),
do: :face
@spec main(args) :: r when args: [binary()], r: :ok
def main(_argv) do
:number = kind({:spades, 7})
:face = kind({:spades, :k})
:number = kind({:rubies, 4}) # should be :diamonds not :rubies
:face = kind({:clubs, :q})
:ok
end
end