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 <brain...@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/ms >>> gid/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-talk+unsubscr...@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 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/CABf3pCmnvMWt3xqvOC3Yim06XpLoSRkqzYqjPUoSp1HurGQbuw%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.