small medium large xlarge

Dave_gnome_head_isolated_pragsmall
15 Jul 2013, 03:42
Dave Thomas (390 posts)
  • You’re going to start creating a server that implements a stack. The call that initializes your stack will pass in a list that is the initial stack contents.

    For now, only implement the pop interface. It’s acceptable for your server to crash if someone tries to pop from an empty stack.

    For example, if initialized with [5,"cat",9], successive calls to pop will return 5, "cat", and 9.

Generic-user-small
25 Aug 2013, 20:17
Steve Downey (2 posts)
defmodule MyStack.Stack do
  use GenServer.Behaviour      

  def init(list)           
  when is_list(list) do
    { :ok, list }
  end

  def handle_call(:pop, _from, list) do
    [head | tail] = list
    { :reply, head, tail }
  end

end
200-g_pragsmall
10 Oct 2014, 11:41
Aleksey Gureiev (11 posts)

Steve, you can pattern-match head-tail as well:

def handle_call(:pop, _from, [head|tail]) do
  { :reply, head, tail }
end
Generic-user-small
15 Jan 2015, 19:15
Pierre Sugar (57 posts)
defmodule Stack.Stack do
  use GenServer

  def handle_call(:pop, _from, current_stack) when current_stack == [] do
    { :reply, :empty, [] }
  end
  def handle_call(:pop, _from, current_stack) do
    [ top | tail ] = current_stack
    { :reply, top, tail }
  end
end
Profile_pragsmall
21 Jan 2015, 10:45
Michele Costa (4 posts)

Hi,

it seems to me that you’ve implemented the SHIFT method, returning the first element of the list, not the POP method, returning the last one.

A more correct return tumple will be (cannot format code with triple tilde…): {:reply, List.last(current_list), List.delete_at(current_list, -1)}

Greetings Mike

U0x0gcxz_pragsmall
05 Apr 2015, 15:52
John Bohn (5 posts)

Yeah, it’s a bit weird. The “spec” says to return 5, “cat”, 9 from [5, “cat”, 9] which would indeed be a shift, but it’s referred to as pop. Just a bit confusing in the book what’s really being called for. Anyway, here’s my implementation of pop that actually is a shift.

defmodule Stack.Server do
  use GenServer

  def init(stack)
  when is_list(stack) do
    { :ok, stack }
  end

  def handle_call(:pop, _from, []), do: raise "Empty stack"
  def handle_call(:pop, _from, [head | tail]) do
    { :reply, head, tail }
  end
end
C2f77d9bcc71d1f9ddabd89a8ddf9615_pragsmall
17 Jul 2015, 03:25
Rebecca Skinner (6 posts)

Haha I had the same confusion with shift/pop. But in the end I went with the example output the book gave, which was for shift.

defmodule Stack.Server do
  use GenServer

  def handle_call(:pop, _from, []),          do: {:reply, nil, []}
  def handle_call(:pop, _from, [head|tail]), do: {:reply, head, tail}
end

Looks pretty similar to all other examples here, but I added the nicety of just returning nil if the list was empty. Crashes are so inelegant.

Generic-user-small
05 Aug 2015, 21:06
Thomas Punt (1 post)

Here’s my solution for implementing an actual pop operation (not shift):

defmodule Sequence.Server do
  use GenServer

  def handle_call(:pop, _from, stack) do
    last_item = List.last(stack)
    new_list = List.delete(stack, last_item)

    {:reply, last_item, new_list}
  end
end

It also means nil will be returned when the list is empty.

Generic-user-small
13 Aug 2015, 17:01
Jim Kane (6 posts)

It’s not stated explicitly in the book at this point, but I have surmised that calling start_link invokes the first handle_call function defined in the module. I wanted an explicit stack setter so I put that first:

defmodule Stack.Server do
  use GenServer

  def handle_call({:set_stack,stack_contents}, _from, _stack_contents) do
    { :reply, nil, stack_contents }
  end

  def handle_call(:pop, _from,  [ head | tail ]) do
    { :reply, head, tail }
  end

  def handle_call(:pop, _from, []) do
    { :reply, nil, [] }
  end

end
Generic-user-small
17 Aug 2015, 22:42
Stefan Chrobot (13 posts)

The book does not say it explicitly, but I think the stack is meant to grow from right to left, i.e. head of the list is the top of the stack. It’s an implementation detail, but it improves performance of pop and push.

Here’s my take with case:

defmodule StackServer do
  use GenServer

  def handle_call(:pop, _client_pid, stack) do
    case stack do
      [] ->
        {:reply, nil, stack}
      [head|tail] ->
        {:reply, head, tail}
    end
  end
end
Generic-user-small
01 Dec 2015, 14:17
Brett Wise (3 posts)

For everyone in the thread thinking that our author made a mistake when he said implement pop I’m here to tell you that he did not. I reckon most of you are thinking in terms of Javascript where shift is the method you use to remove the first element of the array?

At any rate the keyword to pay attention to here is stack. Dave said start a server that implements a stack. I believe when he was writing this Dave had the abstract data type in mind. And as you probably know when we are using the word “stack” in the context of abstract data types, a stack is a LIFO (last in first out) structure. As such, “pop” is commonly used in this context to mean removing the first element on the structure.

But don’t just take my word for it: https://en.wikipedia.org/wiki/Stack_(abstract_data_type)

Generic-user-small
17 Dec 2015, 11:46
Oleksandr Glagoliev (1 post)
defmodule Server do
  use GenServer

  def handle_call(:pop, _from, stack) do
    {:reply, List.last(stack), List.delete_at(stack, -1)}
  end

end

One more implementation from me.

Generic-user-small
10 Jan 2017, 13:16
john invictus (5 posts)

I thought it a good idea to raise an empty exception stead of returning :nill Here is my solution

defmodule Sequence.Stack do
  use GenServer

  def handle_call(:pop, _from, []), do: raise "Empty stack"

  def handle_call(:pop, _from,   [head|tail]) do
    {:reply, head, tail}
  end
end
Generic-user-small
16 Feb 2017, 00:16
Oleg (15 posts)

Not going to blow up if stack is empty though

defmodule StackServer do
  use GenServer

  def handle_call(:pop, _from, stack) do
    {value, rest} = List.pop_at(stack, -1)
    {:reply, value, rest}
  end
end
Generic-user-small
25 Apr 2017, 09:30
Zoltán Vincze (4 posts)
defmodule Sequence.PopServer do

  use GenServer

  def handle_call(:pop, _from, [ head | tail ]) do
    { :reply, head, tail }
  end

end
Generic-user-small
04 May 2017, 05:51
Teddys López G (5 posts)
defmodule ServerStack.Stack do
  use GenServer

  def handle_call(:pop, _from, current_stack) when current_stack == [] do
    {:reply, :empty, []}
  end

  def handle_call(:pop, _from, current_stack) do
    [top|tail] = current_stack
    {:reply, top, tail}
  end
end
Generic-user-small
19 May 2017, 01:43
Derek Hubbard (2 posts)
defmodule Stack.Server do
  use GenServer

  def handle_call(:pop, _from, [head | tail]) do
    { :reply, head, tail }
  end
end
You must be logged in to comment