erlang 转换为'any()'是否是使透析器接受ETS匹配模式的好解决方案?

wooyq4lh  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(130)

Is casting to any() a good solution for having Dialyzer accept ETS match patterns?
Dialyzer and match specifications don't play well together, and there doesn't seem to be a standard solution:

Here's a complete example of the solution I'm considering. If matcher('_') on the last line is changed to '_' then Dialyzer complains about a bad record construction, but with the matcher/1 function all seems to be well:

-module(sample).
-record(rec, {field :: number}).
-export([main/1]).

-type matchvar() :: '$1' | '$2' | '$3' | '$4' | '$5' | '$6' | '$7' | '$8' | '$9' | '$10' | '$11' | '$12' | '$13' | '$14' | '$15' | '$16' | '$17' | '$18' | '$19' | '$20' | '$21' | '$22'.

-spec matcher('_' | matchvar()) -> any().
matcher(X) ->
    case node() of
        '$ will never match' -> binary_to_term(<<>>);
        _ -> X
    end.

main(_Args) ->
    ets:match('my_table', #rec{field = matcher('$1')}, 1).

This works because Dialyzer can't tell statically that the unreachable first clause of matcher/1 is unreachable. Since binary_to_term/1 returns any() , Dialyzer infers the return type of matcher/1 to be any() .
Is this trick a good way of keeping Dialyzer happy when working with match specs? By "good," I mean:

  • low runtime cost
  • few footguns
  • there isn't a better (safer, faster, more ergonomic) way

I peeked at the implementation of node() and think it's just a pointer dereference, so cost should be low. And '$ will never match' will really never match because node()always returns an atom with an @ in it . But there must be a better way.
There are really two questions here, that I've combined to avoid the X Y Problem :

  1. Is the technique above a good way to get Dialyzer to treat something as any() ?
  2. Is getting Dialyzer treat matcher('_') as any() a good solution for working with match specifications?
n53p2ov0

n53p2ov01#

我不认为这是一个好的解决方案,因为你在编译时做了无用的工作(无论多么小)来满足一些东西,这样做是在欺骗透析器。
当出现这种情况时,我通常会扩展记录以包含匹配变量并使用它(通常我的记录是-opaque,因此字段类型在构造函数中控制)。
您可以始终只导出实际类型的子类型,而不使用-opaque(详细说明Pierre Krafft's comment from ERL-892):
第一个

相关问题