Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
A Brief Introduction to Dialyzer and Proper
Search
Christopher Meiklejohn
February 02, 2014
Programming
140
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
A Brief Introduction to Dialyzer and Proper
Christopher Meiklejohn
February 02, 2014
More Decks by Christopher Meiklejohn
See All by Christopher Meiklejohn
Towards a Solution to the Red Wedding Problem
cmeiklejohn
0
440
Language Support for Cloud-Scale Distributed Systems
cmeiklejohn
0
590
Towards a Systems Approach to Distributed Programming
cmeiklejohn
3
390
Scaling a Startup with a 21st Century Programming Language
cmeiklejohn
0
430
Practical Evaluation of the Lasp Programming Model at Scale
cmeiklejohn
4
2.8k
Just-Right Consistency - Closing the CAP Gap
cmeiklejohn
3
320
Declarative, Convergent, Edge Computation
cmeiklejohn
1
240
Just-Right Consistency - Closing the CAP Gap
cmeiklejohn
3
1.4k
A Certain Tendency of the Database Community
cmeiklejohn
0
500
Other Decks in Programming
See All in Programming
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
140
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
810
Go言語とトイモデルで学ぶTransformerの気持ち / fukuokago23-transformer
monochromegane
0
130
AI時代、エンジニアはどう育つのか -未経験エンジニアの成長を間近で見て考えたこと-
thasu0123
0
140
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
140
AIエージェントで 変わるAndroid開発環境
takahirom
2
680
【やさしく解説 設計編・中級 #4】ルールの寿命と、システムの年輪
panda728
PRO
2
150
yield再入門 #phpcon
o0h
PRO
0
630
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
150
AIキャラアプリkaiwaの低遅延音声通話基盤をどう作ったか - AWS Gravitonで支える低遅延・低コストAI Agent基盤
mogamit
0
170
LaravelLive Japan の裏方のすべて — 第188回 PHP勉強会@東京 (2026-06-24)
suguruooki
2
150
どこまでゆるくて許されるのか
tk3fftk
0
510
Featured
See All Featured
Practical Orchestrator
shlominoach
191
11k
Raft: Consensus for Rubyists
vanstee
141
7.6k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
410
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
1
810
Statistics for Hackers
jakevdp
799
230k
Google's AI Overviews - The New Search
badams
0
1.1k
Designing Powerful Visuals for Engaging Learning
tmiket
1
450
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
490
How to make the Groovebox
asonas
2
2.3k
My Coaching Mixtape
mlcsv
0
170
Transcript
Dialyzer / PropEr Christopher Meiklejohn Basho Technologies, Inc.
Static analysis tool for Erlang Dialyzer
Based on success typings Dialyzer
-opaque gcounter() :: orddict:orddict(). ! -type gcounter_op() :: increment |
{increment, pos_integer()}. ! %% @doc Create a new, empty `gcounter()' -spec new() -> gcounter(). new() -> orddict:new(). ! %% @doc Create a `gcounter()' with an initial update -spec new(term(), pos_integer()) -> gcounter(). new(Id, Count) when is_integer(Count), Count > 0 -> {ok, Cnt} = update({increment, Count}, Id, new()), Cnt.
%% @doc Create a `gcounter()' with an initial update -spec
new(term(), atom()) -> gcounter(). new(Id, Count) when is_integer(Count), Count > 0 -> {ok, Cnt} = update({increment, Count}, Id, new()), Cnt.
riak_dt_gcounter.erl:63: Invalid type specification for function riak_dt_gcounter:new/2. The success typing
is (_,pos_integer()) -> riak_dt_gcounter:gcounter()
%% @doc Create a `gcounter()' with an initial update -spec
new(riak_dt:actor(), pos_integer()) -> gcounter(). new(Id, Count) when is_integer(Count), Count > 0 -> {ok, Cnt} = update({increment, Count}, Id, new()), Cnt. ! %% @doc `increment' the entry in `GCnt' for `Actor' by 1 or `{increment, Amt}'. %% returns an updated `gcounter()' or error if `Amt' is not a `pos_integer()' -spec update(gcounter_op(), riak_dt:actor(), gcounter()) -> {ok, gcounter()}. update(increment, Actor, GCnt) -> {ok, increment_by(1, Actor, GCnt)}; update({increment, Amount}, Actor, GCnt) when is_integer(Amount), Amount > 0 -> {ok, increment_by(Amount, Actor, GCnt)}.
riak_dt_gcounter.erl:64: Function new/2 has no local return riak_dt_gcounter.erl:65: The call
riak_dt_gcounter:update({'incremet',pos_integer()},Id::any(),riak_dt_g counter:gcounter()) breaks the contract (gcounter_op(),riak_dt:actor(),gcounter()) -> {‘ok',gcounter()}
%% @doc Create a `gcounter()' with an initial update -spec
new(riak_dt:actor(), pos_integer()) -> gcounter(). new(Id, Count) when is_integer(Count), Count > 0 -> {ok, Cnt} = update({increment, Count}, Id, new()), Cnt. ! %% @doc `increment' the entry in `GCnt' for `Actor' by 1 or `{increment, Amt}'. %% returns an updated `gcounter()' or error if `Amt' is not a `pos_integer()' -spec update(gcounter_op(), riak_dt:actor(), gcounter()) -> {ok, gcounter()}. update(increment, Actor, GCnt) -> {ok, increment_by(1, Actor, GCnt)}.
riak_dt_gcounter.erl:64: Function new/2 has no local return riak_dt_pncounter.erl:216: The created
fun has no local return
Demo
Property-based testing tool PropEr
Inspired by QuickCheck; licensed under GPL PropEr
Full integration with Erlang specifications PropEr
Simple
-module(simple_props). ! %% Properties are automatically exported. -include_lib("proper/include/proper.hrl"). ! %%
Functions that start with prop_ are considered properties prop_t2b_b2t() -> ?FORALL(T, term(), T =:= binary_to_term(term_to_binary(T))).
1> c(simple_props). {ok,simple_props} 2> proper:quickcheck(simple_props:prop_t2b_b2t()). ................................................... ................................................. OK: Passed 100
test(s) true
Stack
-spec new() -> stack(_T). new() -> {0, []}. ! -spec
push(T, stack(T)) -> stack(T). push(X, {N,Elems}) -> {N+1, [X|Elems]}. ! -spec pop(stack(T)) -> {T,stack(T)}. pop({0, []}) -> throw(stack_empty); pop({N, [Top|Rest]}) when N > 0 -> {Top, {N-1,Rest}}.
prop_push_pop() -> ?FORALL({X,S}, {integer(),stack(integer())}, begin {Y,_} = pop(push(X,S)), X =:=
Y end).
Eshell V5.10.3 (abort with ^G) 1> proper:quickcheck(stack:prop_push_pop()). ...................................................................... .............................. OK:
Passed 100 test(s). true
Lists
prop_reverse() -> ?FORALL(X, list(integer()), lists:reverse(lists:reverse(X)) == X).
7> proper:quickcheck(lists_proper:prop_reverse()). ...................................................................... .............................. OK: Passed 100 test(s). true
prop_delete() -> ?FORALL(L, non_empty(list(integer())), ?FORALL(X, elements(L), not lists:member(X, (lists:delete(X, L))))).
16> proper:quickcheck(lists_proper:prop_delete()). ........! Failed: After 9 test(s). [-1,-1] -1 !
Shrinking (0 time(s)) [-1,-1] -1 false 17>
17> proper:quickcheck(lists_proper:prop_delete()). ..................................! Failed: After 35 test(s). [2,-10,-7,13,70,2] 2 !
Shrinking ......(6 time(s)) [2,2] 2 false
prop_delete() -> ?FORALL(L, non_empty(list(integer())), ?FORALL(X, elements(L), lists:foldl(fun(Y, Acc) -> case
Y of X -> Acc + 1; _ -> Acc end end, 0, L) - 1 == lists:foldl(fun(Y, Acc) -> case Y of X -> Acc + 1; _ -> Acc end end, 0, lists:delete(X, L)))).
22> proper:quickcheck(lists_proper:prop_delete()). ...................................................................... .............................. OK: Passed 100 test(s). true
Thanks!