How to check a value is the return value of `Stream.resource/3`?

When using general stream function, such as Stream.timer/1, it returns:

#Stream<[
  enum: #Function<61.58486609/2 in Stream.unfold/2>,
  funs: [#Function<55.58486609/1 in Stream.take_after_guards/2>]
]>

which is very easy to detect the type with is_struct(stream, Stream).

But, when using Stream.resource/3, the return value is something like #Function<51.58486609/2 in Stream.resource/3>. For example:

    stream = Stream.resource(
      fn -> File.open!("sample") end,
      fn file ->
        case IO.read(file, :line) do
          data when is_binary(data) -> {[data], file}
          _ -> {:halt, file}
        end
      end,
      fn file -> File.close(file) end
    )
    # Function<51.58486609/2 in Stream.resource/3>

    is_struct(stream, Stream)  # false

Is there any way to detect the return value of Stream.resource/3 as a stream?

Streams are just „lazy“ enumerables, so data implementing a protocol. You cannot know in advance for which forms of data the protocol is implemented, so the answer is: no.

You can find a more extensive explanation here: Stream module functions returning functions

1 Like

Found a tip about how to indicating a stream:

# wrap Stream with {:stream, _}, for example:
{:stream, Stream.resource(_, _, _)}

# pattern match {:stream, stream} when you want to handle a stream.
case body do
  {:stream, stream} -> Enum.into(stream, <<>>)
  _ -> body
end

From httpoison/lib/httpoison/base.ex at a3c7c02e57dac38590f2e476d0814a567c2025f2 · edgurgel/httpoison · GitHub

Why do you need to know if it’s a stream?

Why can’t you just treat it as an Enumerable and continue using Enum or Stream functions on it?

1 Like