Queues do not give control over that structure though. Fred wrote a good
article on zippers: http://ferd.ca/yet-another-article-on-zippers.html

On Monday, August 29, 2016, Ben Wilson <benwilson...@gmail.com> wrote:

> Sounds at least a bit like http://erlang.org/doc/man/queue.html
>
> On Monday, August 29, 2016 at 6:57:08 PM UTC-4, OvermindDL1 wrote:
>>
>> Entirely different concepts.  :-)
>>
>> 'zipping' a list means combining multiple lists into a single list of
>> tuple/lists, which is what Enum/Stream does.
>>
>> A Zipper data structure is essentially a tuple of two lists, for example:
>> {[], [1, 2, 3, 4]}
>> -> Move right
>> -> {[1], [2, 3, 4]}
>> -> Move right
>> -> {[2, 1], [3, 4]}
>> -> Move right
>> -> {[3, 2, 1], [4]}
>> -> Move left
>> -> {[2, 1], [3, 4]}
>>
>> It is basically a way of iterating backwards and forward through a list
>> (which is what a BF interpreter does to access its memory) in a very
>> efficient, functional, immutable method.  The left side holds the reversed
>> 'data' to the left of your 'cursor', and the right holds the 'data' to the
>> right of your 'cursor', where the cursor is just the current position along
>> the entire structure.
>>
>> Zippers can also be more complicated as well, allowing you to efficiently
>> and immutable walk along an entire tree structure back and forth
>> efficiently.
>>
>>
>> On Monday, August 29, 2016 at 4:28:46 PM UTC-6, Ben Wilson wrote:
>>>
>>> Can you elaborate on what you'd like out of a zipper library not found
>>> in Stream/Enum?
>>>
>>> On Monday, August 29, 2016 at 10:45:55 AM UTC-4, OvermindDL1 wrote:
>>>>
>>>> Awesome!  Been wanting a good Elixir Zipper library, the others I'd
>>>> found were for Erlang and had different usages.  :-)
>>>>
>>>> Easy to do it yourself though of course, but libraries also help
>>>> document usage instead of just using a {[],[]} as a zipper.  :-)
>>>>
>>>> On Monday, August 29, 2016 at 5:49:10 AM UTC-6, Brian Bugh wrote:
>>>>>
>>>>> Thanks for the great idea! I forgot about zippers. This was exactly
>>>>> what I needed. There was a zipper tree library on hex but it was overkill
>>>>> for what I needed, so I made my own: https://hex.pm/packages/z
>>>>> ipper_list
>>>>>
>>>>> On Wednesday, August 24, 2016 at 10:00:29 AM UTC-5, OvermindDL1 wrote:
>>>>>>
>>>>>> Instead of holding 'data' and a 'dataptr' you could make the `data`
>>>>>> data structure a zipper where the location of the zipper is the ptr.  
>>>>>> Would
>>>>>> be very efficient.
>>>>>>
>>>>>> https://en.wikipedia.org/wiki/Zipper_(data_structure)
>>>>>>
>>>>>> There might even be a library or two on it on hex.pm.  :-)
>>>>>>
>>>>>>
>>>>>> On Tuesday, August 23, 2016 at 5:31:11 PM UTC-6, Brian Bugh wrote:
>>>>>>>
>>>>>>> Ah you're right! Very clever. That's awesome, thanks for explaining.
>>>>>>>
>>>>>>> The implementation I posted was doing the < and > commands
>>>>>>> backwards, because I was thinking about it being cheaper to prepend to
>>>>>>> lists instead of appending, but there's no way around it.
>>>>>>>
>>>>>>> The Wikipedia article about BF isn't very helpful. I've written an
>>>>>>> interpreter successfully in Ruby, but I'm doing a clean room 
>>>>>>> implementation
>>>>>>> of it in Elixir so I can't "cheat".
>>>>>>>
>>>>>>> The < and > commands assume you have a data pointer list of infinite
>>>>>>> size, 0 based. Something like Array.new(n, 0) in Ruby. So if you run a 
>>>>>>> BF
>>>>>>> program like *<<<<<<+*, you'd end up with a data structure of [1,
>>>>>>> 0, 0, 0, 0, 0], hence the required list manipulation.
>>>>>>>
>>>>>>> - Brian
>>>>>>>
>>>>>>> On Aug 23, 2016, at 4:24 PM, Torben Hoffmann <torben...@gmail.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>> Hi Brian,
>>>>>>>
>>>>>>> Looking at what your code does and what I suggested I don't see a
>>>>>>> difference.
>>>>>>>
>>>>>>> Your command/2 will subtract 1 from dataprt and if dataptr < 0 then
>>>>>>> you will reset dataptr to 0 and pop data.
>>>>>>>
>>>>>>> My solution took the liberty of saying "if dataptr=0 (before you
>>>>>>> subtract) we have to pop data otherwise we subtract one from dataprt and
>>>>>>> that is it".
>>>>>>> That should do the same as your code, because if dataptr=0 when you
>>>>>>> run your command/2 function you will end up with dataptr=-1 before 
>>>>>>> calling
>>>>>>> do_trim, which will reset it to 0 and pop data.
>>>>>>>
>>>>>>> Reading the Brianfuck page on Wikipedia seems to suggest that the <
>>>>>>> command should only decrement the dataptr, so I am not sure what the pop
>>>>>>> you are doing with tl is good for. But then again, Brainfuck is not
>>>>>>> supposed to be easy to understand...
>>>>>>>
>>>>>>> I actually can't believe that I am going to write the following...
>>>>>>> ;-)
>>>>>>>
>>>>>>> I would consider using two lists to hold the array of cells. Say,
>>>>>>> left and right fields in your state.
>>>>>>> Initially we would have left=[] and right= "a bunch of zeros".
>>>>>>> Then we get something like this
>>>>>>>
>>>>>>>   def command("<", state = %{left: []}) do
>>>>>>>     state # we silently do nothing when moving too far
>>>>>>>   end
>>>>>>>
>>>>>>>   def command("<", state = %{left: [h|t]} do
>>>>>>>     %{state | left: t, right: [h | state.right]}
>>>>>>>   end
>>>>>>>
>>>>>>>   # we always leave one element in right as that is the end of our
>>>>>>> world
>>>>>>>   def command(">", state = %{right: [_]} do
>>>>>>>     state
>>>>>>>   end
>>>>>>>
>>>>>>>   def command(">", state = %{right: [h|t]}) do
>>>>>>>     %{state | left: [h | state.left], right: t}
>>>>>>>   end
>>>>>>>
>>>>>>>   def command("+", state = %{right: [h|t]}) do
>>>>>>>     %{state | right: [ h+1 | t ]} # should probably do some overflow
>>>>>>> handling if we want to keep having a cell as a byte
>>>>>>>   end
>>>>>>>   ...
>>>>>>>   def command("[", state = %{right: [0|t]}) do
>>>>>>>     state
>>>>>>>   end
>>>>>>>
>>>>>>>   def command("[", state) do
>>>>>>>     # this is where the fun starts, now we need to enter a mode
>>>>>>> where we loop the code
>>>>>>>     # until we have balanced out [ and ].
>>>>>>>     ...
>>>>>>>   end
>>>>>>>
>>>>>>> And already here I can see that using command with just two
>>>>>>> arguments will probably be hurtful in the long run.
>>>>>>> Perhaps the function should be called interpret and take a list of
>>>>>>> chars as the first argument and simply peel off the first element.
>>>>>>> When we reach a loop we have to start accumulating the commands in
>>>>>>> case the loop has to run more than once.
>>>>>>> But if we call a loop function that executes commands and return the
>>>>>>> collected loop body as well as an updated state, then we simply have to
>>>>>>> check the value at the data pointer when the loop has been collected. 
>>>>>>> If it
>>>>>>> is zero we throw away the collected program, if not we re-insert the
>>>>>>> collected program in front of the rest of the program and call interpret
>>>>>>> again.
>>>>>>>
>>>>>>> Now I am almost tempted to go write the full interpreter, but
>>>>>>> luckily for me it is late at my end right now, so I'll have to see if I 
>>>>>>> am
>>>>>>> up for it tomorrow!!
>>>>>>>
>>>>>>> Cheers,
>>>>>>> Torben
>>>>>>>
>>>>>>>
>>>>>>> On 23 August 2016 at 15:55, Brian Bugh <brai...@gmail.com> wrote:
>>>>>>>
>>>>>>>> It turns out that I think my assumption about how the BF
>>>>>>>> interpreter works is wrong, but I want to continue this discussion 
>>>>>>>> because
>>>>>>>> while my interpreter may be bad, I still don't know the answer to my 
>>>>>>>> Elixir
>>>>>>>> question. :)
>>>>>>>>
>>>>>>>> Torben - thanks for the idea! I did try it with function pattern
>>>>>>>> matching. However, the actual command is dataptr - 1 , so that
>>>>>>>> needs to run first. *Then* if the dataptr is less than 0, the
>>>>>>>> other check runs.  The way you've suggested it in the first command
>>>>>>>> assumes that the < command has already been run. :)
>>>>>>>>
>>>>>>>> Here's what I tried with pattern matching, which is even less
>>>>>>>> comprehensible than that simple little if statement at the top.
>>>>>>>>
>>>>>>>>   def command("<", state = %{data: data, dataptr: dataptr}) when
>>>>>>>> is_list(data) and is_integer(dataptr) and dataptr >= 0 do
>>>>>>>>     do_trim(%{state | dataptr: dataptr - 1})
>>>>>>>>   end
>>>>>>>>
>>>>>>>>   def do_trim(state = %{data: data, dataptr: dataptr}) when
>>>>>>>> dataptr < 0 do
>>>>>>>>     %{state | dataptr: 0, data: tl(data) }
>>>>>>>>   end
>>>>>>>>
>>>>>>>>   def do_trim(state = %{data: data, dataptr: dataptr}), do: state
>>>>>>>>
>>>>>>>> Having been a programmer for 23 years, I'm a huge fan of writing
>>>>>>>> code that my tired, burned out, 
>>>>>>>> working-on-the-weekend-because-release-date-is-Monday
>>>>>>>> future self won't have to think about too hard to understand.
>>>>>>>>
>>>>>>>> Nothing I've come up with so far is as clear as that simple little
>>>>>>>> if statement.
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> On Tuesday, August 23, 2016 at 8:24:51 AM UTC-5, Torben Hoffmann
>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>> Hi Brian,
>>>>>>>>>
>>>>>>>>> How about this?
>>>>>>>>>
>>>>>>>>>   def command("<", state= %{dataprt: 0}) do
>>>>>>>>>     {:ok, %{state | data: tl(data)}}
>>>>>>>>>   end
>>>>>>>>>
>>>>>>>>>   def command("<", state) do
>>>>>>>>>     {:ok, %{state | dataprt: state.dataptr - 1}}
>>>>>>>>>   end
>>>>>>>>>
>>>>>>>>> By using the pattern matching in the function clauses you get code
>>>>>>>>> that reads like your description of the problem.
>>>>>>>>> I.e., if the dataptr is zero pop the data stack otherwise
>>>>>>>>> decrement the dataptr.
>>>>>>>>>
>>>>>>>>> Cheers,
>>>>>>>>> Torben
>>>>>>>>>
>>>>>>>>> On 23 August 2016 at 15:08, Brian Bugh <brai...@gmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> Here's another ugly one I came up with (with the complete
>>>>>>>>>> function for reference) that is even worse.
>>>>>>>>>>
>>>>>>>>>> def command("<", state = %{data: data, dataptr: dataptr}) when
>>>>>>>>>> is_list(data) and is_integer(dataptr) and dataptr >= 0 do
>>>>>>>>>>   dataptr = dataptr - 1
>>>>>>>>>>
>>>>>>>>>>   state = case state do
>>>>>>>>>>     %{dataptr: dataptr} when dataptr < 0 -> %{state | dataptr: 0,
>>>>>>>>>> data: tl(data) }
>>>>>>>>>>     _ -> state
>>>>>>>>>>   end
>>>>>>>>>>
>>>>>>>>>>   {:ok, %{state | dataptr: dataptr, data: data}}
>>>>>>>>>> end
>>>>>>>>>>
>>>>>>>>>> Usually when I get stuck like this it means I'm overthinking
>>>>>>>>>> something.
>>>>>>>>>>
>>>>>>>>>> Any suggestions?
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Tuesday, August 23, 2016 at 7:51:22 AM UTC-5, Brian Bugh wrote:
>>>>>>>>>>>
>>>>>>>>>>> For fun and profit, I am writing a Brainf**k interpreter in
>>>>>>>>>>> Elixir.
>>>>>>>>>>>
>>>>>>>>>>> In one particular case, a data pointer should be decremented,
>>>>>>>>>>> and if it's less than 0, it should be set to 0 and the top of the 
>>>>>>>>>>> data
>>>>>>>>>>> stack should be popped off.
>>>>>>>>>>>
>>>>>>>>>>> I assumed that I should write something like this (which passes
>>>>>>>>>>> my :
>>>>>>>>>>>
>>>>>>>>>>> dataptr = dataptr - 1
>>>>>>>>>>>
>>>>>>>>>>> if dataptr < 0 do
>>>>>>>>>>>   dataptr = 0
>>>>>>>>>>>   data = tl data
>>>>>>>>>>> end
>>>>>>>>>>>
>>>>>>>>>>> but I get a compiler warning when I do this. It suggested that I
>>>>>>>>>>> use the assignment form of *if*, which is fine, but I can't
>>>>>>>>>>> find an elegant way to write the code now. This is what I came up 
>>>>>>>>>>> with,
>>>>>>>>>>> which seems uglier and unnecessarily verbose for future readers. 
>>>>>>>>>>> The first
>>>>>>>>>>> form above is much more readable.
>>>>>>>>>>>
>>>>>>>>>>> [dataptr | data] = if dataptr < 0 do
>>>>>>>>>>>   [0 | tl data]
>>>>>>>>>>> else
>>>>>>>>>>>   [dataptr | data]
>>>>>>>>>>> end
>>>>>>>>>>>
>>>>>>>>>>> Is there a better Elixir-way to write this?
>>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> You received this message because you are subscribed to the
>>>>>>>>>> Google Groups "elixir-lang-talk" group.
>>>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>>>> send an email to elixir-lang-ta...@googlegroups.com.
>>>>>>>>>> To view this discussion on the web visit
>>>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-talk/bfcb8bdf-
>>>>>>>>>> aede-4955-ac50-a6ac6dde3e5a%40googlegroups.com
>>>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-talk/bfcb8bdf-aede-4955-ac50-a6ac6dde3e5a%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>>>> .
>>>>>>>>>>
>>>>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> http://www.linkedin.com/in/torbenhoffmann
>>>>>>>>> @LeHoff
>>>>>>>>>
>>>>>>>> --
>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>> Groups "elixir-lang-talk" group.
>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>> send an email to elixir-lang-ta...@googlegroups.com.
>>>>>>>> To view this discussion on the web visit
>>>>>>>> https://groups.google.com/d/msgid/elixir-lang-talk/743c6c3e-
>>>>>>>> 0def-4cf6-8dee-2338a19c0ef6%40googlegroups.com
>>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-talk/743c6c3e-0def-4cf6-8dee-2338a19c0ef6%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>>>>>> .
>>>>>>>>
>>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> http://www.linkedin.com/in/torbenhoffmann
>>>>>>> @LeHoff
>>>>>>>
>>>>>>> --
>>>>>>> You received this message because you are subscribed to a topic in
>>>>>>> the Google Groups "elixir-lang-talk" group.
>>>>>>> To unsubscribe from this topic, visit https://groups.google.com/d/to
>>>>>>> pic/elixir-lang-talk/_BPxgTc4VGM/unsubscribe.
>>>>>>> To unsubscribe from this group and all its topics, send an email to
>>>>>>> elixir-lang-ta...@googlegroups.com.
>>>>>>> To view this discussion on the web visit
>>>>>>> https://groups.google.com/d/msgid/elixir-lang-talk/CABf3pCmn
>>>>>>> vMWt3xqvOC3Yim06XpLoSRkqzYqjPUoSp1HurGQbuw%40mail.gmail.com
>>>>>>> <https://groups.google.com/d/msgid/elixir-lang-talk/CABf3pCmnvMWt3xqvOC3Yim06XpLoSRkqzYqjPUoSp1HurGQbuw%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>>>> .
>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>
>>>>>>> --
> You received this message because you are subscribed to the Google Groups
> "elixir-lang-talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to elixir-lang-talk+unsubscr...@googlegroups.com
> <javascript:_e(%7B%7D,'cvml','elixir-lang-talk%2bunsubscr...@googlegroups.com');>
> .
> To view this discussion on the web visit https://groups.google.com/d/
> msgid/elixir-lang-talk/30f5bbd0-b3d3-4309-bf35-
> 6707cf3d723e%40googlegroups.com
> <https://groups.google.com/d/msgid/elixir-lang-talk/30f5bbd0-b3d3-4309-bf35-6707cf3d723e%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>


-- 


*José Valim*
www.plataformatec.com.br
Skype: jv.ptec
Founder and Director of R&D

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elixir-lang-talk+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-talk/CAGnRm4LJYffw%2B4jjHp0qJzRH8c09gc2E2t%3DTJTcaALBtnn-aAA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to