Cannot return a list of the items in the queue in the same order

Hi guys,

Can anyone advice how to solve the next problem in this program:

defmodule QueueLoader do
 
 require Wdata
     
 {_result, queue} = Wdata.start_link(EQueue.new())
 
 # Put the list items in the queue
 
 Enum.each([1,2,3,4,5], fn item -> Wdata.add_agent(queue,item) end)
 
 # Pop 3 items from the queue
 
 for item <- 1..3 , do: Wdata.pop_agent(queue) # Ok, this works.

 # Returns a list of the items in the queue in the same order;
 # the front item of the queue must become the head of the list
 
 EQueue.to_list(queue) |> IO.inspect()
 
 end

When I compile this program it gives the next compilation error.

== Compilation error in file lib/queue3.ex ==
** (FunctionClauseError) no function clause matching in EQueue.to_list/1

The following arguments were given to EQueue.to_list/1:

    # 1
    #PID<0.94.0>

Attempted function clauses (showing 1 out of 1):

    def to_list(%EQueue{data: queue})

lib/e_queue.ex:83: EQueue.to_list/1
lib/queue3.ex:56: (module)
(stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

So I understand the PID refers to a process

Here follows the struct and spec:

defstruct data: :queue.new
@type t :: %EQueue{data: {[any],[any]} }

@doc """
       Returns a list of the items in the queue in the same order;
       the front item of the queue will become the head of the list.

       ## Example
       iex> EQueue.from_list([1, 2, 3, 4, 5]) |> EQueue.to_list
       [1, 2, 3, 4, 5]
       """
  @spec to_list(EQueue.t) :: [any]
  def to_list(%EQueue{data: queue}), do: :queue.to_list(queue)

Many Thanks!

Thiel Chang

I do not know what Wdata is, but I’d guess it’s some kind of agent that holds state. This state seems to be an Equeue.

The you try to convert the agent to a list where you probably should pass in the Wdata s state.

So you should ask that Wdata for its state, and then pass that state into the tolist function.

1 Like

Hi mr NobbZ,

Thanks for your quick response. Yes, I am playing with EQueue.

I have used your suggestion and made a little test program. It works but not really good as I expected. The reason is that I don’t know how to get the state of the EQueue.
I used - pop(state) - to get a state, but as a side effect of the pop statement the list lacks one element of the original list [1…10].

test "Test state of the queue" do
  
  # @times 1..10

    {:ok, queue} = Agent.start_link fn -> EQueue.new end
      Enum.each(@times, fn item -> push_item(queue, item)
    end)
   
    {item, state} = Agent.get(queue, fn state -> case pop(state) do
     {:value, item, queue} -> {item, queue}
     end 
   end)
   
   # The value of state is: #EQueue<[2, 3, 4, 5, 6, 7, 8, 9, 10]>

   assert EQueue.length(state) == 9

   assert state |> EQueue.to_list ==  [2, 3, 4, 5, 6, 7, 8, 9, 10]

   assert Enum.sum(EQueue.to_list(state)) == 54
   
   Agent.stop(queue)
   
  end

So, how do I get the state of the module EQueue; or a module in general?

Best regards,

Thiel

No, the equeu is the state of your agent. You shall retrieve that, should roughly be like Agent.get(pid, & &1). And that is your queue you can convert to a list.

Also why are you having the agent in-between? Why aren’t you playing with the queue until you get it and only then wrap it in an agent until you get the concept of agents? It’s easier to learn a thing at time rather than 2.

Hi Norbert,

Yes, Agent.get(pid, & &1) is the right solution to get the queue state.

I always appreciate your excellent advice and comments in the Elixir forum!

In my case they are a pleasure in learning Elixir.

As a retired software engineer I remember the software engineering class in learning the queue subject. (Now more than 50 years ago e.g Knuth's Fundamental

algorithms )

Best regards,

Thiel

Hi Norbert,

Some feedback.

  I realized to my surprise I forgot my OO-, Ruby, and design

patterns past while doiing functional programming with a narrow
view!

  Of course, an Agent is a kind of OO-class with a state and

methods.

Yes, this was a very funny lesson.

Best regards,

Thiel Chang

1 Like