How to get type info?

type_info = IEx.Helpers.i(foo)

Error:
Function IEx.Helpers.i/1 does not exist.

How do I resolve this issue?

1 Like

The IEx.Helpers are only available in IEx. Can you elaborate on the problem you’re trying to solve?

2 Likes

I’m trying to get precise type information in order to quickly construct a pattern match against the results of a function call rather than trying to figure it out by trial and error. (inspect() isn’t always accurate.)

1 Like

inspect(value, structs: false) should be pretty unambiguous about what the value is. What output do you see?

2 Likes

If you want just type then you can write such function quite easily on your own:

def type(%struct{}), do: {:struct, struct}

def type(input) do
  cond do
    is_atom(input) -> :atom
    is_list(intput) -> :list
    is_binary(input) -> :binary
    is_integer(input) -> :integer
    is_float(input) -> :float
    is_pid(input) -> :pid
    is_tuple(input) -> :tuple
    is_map(input) -> :map
    is_ref(input) -> :ref
    is_port(input) -> :port
    is_bitstring(input) -> :bitstring
    is_function(input) -> :function
  end
end

I think I have covered all possible types there

7 Likes

Maybe only missing:

def type(input) do
  import Record

  cond do
    is_atom(input) -> :atom
    is_list(intput) -> :list
    is_record(input) -> :record
    ...
  end
end
2 Likes

This question gets asked every-so-often so I’m going to be That Guy ™ and ask you for the whole context of your problem if you’re willing to share. In 3+ years of writing Elixir, I’ve never once found myself wanting such a function. Perhaps we could help you refactor into something more idiomatic, if you’re willing. If not, that’s also cool :sunglasses:

9 Likes

is_record/1 could result with weird results in many cases, so I would avoid that there. For example it would return :record for {:ok, 1}.

2 Likes

The first element of a keyword list of arbitrary length was proving difficult for me to pattern match against.

Ex:

iex(1)> foo = [ok: :one, ok: :two, ok: :three]       

iex(2)> inspect(foo, structs: false)
"[ok: :one, ok: :two, ok: :three]"

It seems like this is just a list, but:

iex(3)> [ok: _ | bosh] = foo
** (CompileError) iex:3: misplaced operator |/2

i/1 revealed that it’s really a list of two element tuples:

iex(4)> i(foo) 
Term
  [ok: :one, ok: :two, ok: :three]
Data type
  List
Description
  This is what is referred to as a "keyword list". A keyword list is a list
  of two-element tuples where the first element of each tuple is an atom.
Reference modules
  Keyword, List
Implemented protocols
  Collectable, Enumerable, IEx.Info, Inspect, List.Chars, String.Chars

With this crucial clarification:

iex(5)> [{:ok, _} | bosh] = foo               
[ok: :one, ok: :two, ok: :three]

iex(6)> bosh
[ok: :two, ok: :three]

Which brings us full circle by to my original query:

Thanks for chiming in :slight_smile:

Please see my reply to @benwilson512 here above.

Maybe a keyword list is not the appropriate structure for what You want to do.

I don’t remember having to match on the first element of a keyword list… I use keyword list as function parameters, or in config file.

Unless You don’t own the code, You might help yourself by writing spec.

I can’t reproduce this behavior, even with a file passed to plain elixir:

# in the file bar.exs
IEx.Helpers.i({:ok, nil}) |> IO.inspect()
$ elixir bar.exs 
Term
  {:ok, nil}
Data type
  Tuple
Reference modules
  Tuple
Implemented protocols
  IEx.Info, Inspect
:"do not show this result in output"

(This is 1.14.0 / OTP 25, if that makes a difference)

2 Likes