<div dir="ltr"><div class="gmail_default" style="font-family:arial,helvetica,sans-serif">You can achieve something close to what you are after by using opaque types. Partly re-using your original example:</div><div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br></div><div class="gmail_default" style=""><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-module(string_with_case).</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-opaque lowercase() :: string().</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-opaque uppercase() :: string().</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-type anycase() :: lowercase() | uppercase() | string().</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-export_type([ lowercase/0</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">             , uppercase/0</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">             ]).</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-export([ uppercase/1</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">        , lowercase/1</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">        , need_lower/1</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">        , concat/2</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">        ]).</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-spec lowercase(anycase()) -> lowercase().</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">lowercase(Str) -> string:to_lower(Str).</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-spec uppercase(anycase()) -> uppercase().</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">uppercase(Str) -> string:to_upper(Str).</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-spec need_lower(lowercase()) -> ok. </font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">need_lower(_Lower) -> ok. </font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">-spec concat(anycase(), anycase()) -> string().</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">concat(A, B) -> A ++ B.</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">Note that these two (maybe in your eyes valid) examples will NOT pass dialyzer:</font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif"><br></font></div><div class="gmail_default" style=""><font face="arial, helvetica, sans-serif">string_with_case:need_lower("example"). % FAILS: Breaks opaqueness of string_with_case:lowercase().</font></div><div style="font-family:arial,helvetica,sans-serif"><br></div><div style="font-family:arial,helvetica,sans-serif">string_with_case:lowercase("test") ++ "mixing". % FAILS: Breaks opaqueness of string_with_case:lowercase().</div><div><br></div><div>In other words, all operations involving types uppercase() or lowercase() must take place inside the string_with_case module.</div><div>If you need to operate on a lowercase() as if it were a string outside the string_with_case module, you must provide a to_string function:</div><div><br></div><div>-spec to_string(anycase()) -> string().</div><div>to_string(X) -> X.</div><div><br></div><div>This of course means you would have to call the lowercase/1 or uppercase/1 functions again to convert it back, should you need to</div><div>use the "variant/sort specific" functions of string_with_case on the result. This is however necessary to maintain the guarantees you are trying to achieve.</div><div><br></div><div>//Daniel</div></div></div>