Hi John,

thanks for taking the time to answer, look through the code, write your
own version and explain it. Your solution to reactions makes more sense,
is simpler and doesn't copy. I also learned about new-resizable, like
and with. And I like the use of ?last which simplifies the bounds check.

Well, I'd expect supremum to go by something that starts with "max", if
max is already for 2 objects than maybe maximum and maximum-by would be
nice for a sequence. Either way having it in the docs for searching
would have been enough for me to find the words.

I'll take a look at the docs and hopefully whip up a pull request.

-- 
------------
  Peter Nagy
------------


On 2018-12-11 22:25, John Benediktsson wrote:
> Hi Peter,
> 
> The performance difficulties in your solution arise from using
> ``head*`` which makes a new sequence (allocations, copying into new
> memory, etc.), rather than a lightweight slice which ``head-slice*``
> does.
> 
> You are right that slices are not what you expect, you might find this
> interesting:
> 
>     IN: scratchpad "abcdef" dup 3 head-slice CHAR: D suffix!
> 
>     --- Data stack:
>     "abcDef"
>     T{ slice f 0 3 "abcDef" }
> 
> In-place operations like ``set-nth`` and variations like ``suffix!``
> operate on the underlying sequence.
> 
> The Clojure-like data structures are in ``persistent`` vocabulary. 
> See, for example ``persistent.vectors``.
> 
> Some of your words like ``upper`` are in the standard library
> (``ch>upper``).  Also, I found your version didn't remove the extra
> newline in the input text, which resulted in an answer that was 1 too
> large.
> 
> This looked like a fun puzzle, and I like fun puzzles, so I thought
> I'd implement it and maybe provide another solution which could help
> with learning:
> 
>     USING: ascii fry kernel math sequences ;
> 
> You can tell if two characters match for a possible reaction, if they
> are not the same, but are when made to lowercase.  I also really like
> your subtract and absolute difference should equal 32 approach.
> 
>     : match? ( ch1 ch2 -- ? )
> 
>         2dup = [ 2drop f ] [ [ ch>lower ] bi@ = ] if ;
> 
> My approach uses a stack (either a ``vector`` when processing an
> array, or an ``sbuf`` when processing a string).  If the stack is
> empty (``?last`` returns ``f``), we don't react, otherwise check for a
> match on the last character in the stack.
> 
>     : react? ( accum ch -- ? )
>         [ ?last ] dip over [ match? ] [ 2drop f ] if ;
> 
> An internal word that processes the whole string.  If we react, then
> we pop the last character from the stack, otherwise push the new one
> onto the stack
> 
>     : (react) ( accum seq -- accum )
>         [ 2dup react? [ drop dup pop* ] [ suffix! ] if ] each ;
> 
> The main word that creates a new resizable sequence to use as a stack,
> then applies the reactions:
> 
>     : react ( seq -- seq' )
>         [ [ length ] [ new-resizable ] [ (react) ] tri ] keep like ;
> 
> The part 2 question tries removing each letter, looking for the
> smallest length of reactions:
> 
>     : remove-unit ( seq ch -- seq' )
>         [ [ = ] [ ch>upper = ] 2bi or ] curry reject ;
> 
>     : shortest-react ( seq -- n )
>         "abcdefghijklmnopqrstuvwxyz" [
>             remove-unit react length
>         ] with map infimum ;
> 
> I find that often I experiment with different approaches, sometimes
> using locals and writing in a more applicative style, other times
> starting with small components like ``match?`` and ``react?`` and then
> building up an algorithm around it.  I do like iteration in the
> listener, but also find saving my code and refactoring easier with a
> text file and doing F2 or ``refresh-all``, or using like you are FUEL.
> 
> Also, as for finding words.  We do want to continue improving
> documentation, so if you have contributions there it would be great. 
> It's sometimes useful to just browse a vocabulary and look at all the
> words in a list.  Maybe we could think about adding the first sentence
> of its documentation, if available, which would also help. You can see
> on the help for ``min`` and ``max`` they have related words
> ``supremum`` and ``infimum``.  Maybe those need better names...
> 
> Best,
> John.
> 
> On Tue, Dec 11, 2018 at 8:22 AM <pet...@riseup.net> wrote:
> 
>> On 2018-12-10 16:40, John Benediktsson wrote:
>>> Using fry is convenient.  Due to how we bootstrap factor, we can't
>> use
>>> fry right now in "core" vocabularies, like sequences, so you'll
>> see a
>>> fair amount of curry and compose which are more or less what fry
>> is
>>> doing, just not as clean syntax.
>>>
>>> I love the REPL advent idea, go for it!  And as you learn or hit
>>> roadblocks or have questions, please share.
>>>
>>> You can see how supremum-by is implemented by clicking on it in an
>>> expression, or doing ``see``.  It uses ``after?`` instead of
>> ``>``,
>>> which allows it to compare other kinds of objects with ``<=>``
>> when
>>> numbers are not passed in.
>>>
>>> Also, you might try using ``map-reduce`` which is a little faster
>> than
>>> using ``unclip-slice`` and ``reduce``, (and using ``_ bi@``
>> instead of
>>> ``[ _ call ] bi@`` to simplify):
>>>
>>> : max-by ( seq quot -- result )
>>> [ ] swap '[ [ _ bi@ > ] 2keep ? ] map-reduce ; inline
>>>
>>> Best,
>>> John.
>>>
>>> On Mon, Dec 10, 2018 at 6:46 AM Alexander Ilin <ajs...@yandex.ru>
>>> wrote:
>>>
>>>> Hey there!
>>>>
>>>> Sure, you can ask us here. I'm on sick leave, so got plenty of
>>>> time.
>>>> Coincidentally, working on my Factor hobby project.
>>>>
>>>> What you're looking for is called supremum-by.
>>>>
>>>> Terminology is a bit uncommon. Look up supremum and infimum in
>> the
>>>> help system.
>>>>
>>>> 10.12.2018, 17:06, "pet...@riseup.net" <pet...@riseup.net>:
>>>>> Hello fellow concatenative fans.
>>>>>
>>>>> I'm working my way through this year's advent of code[0]. I'm
>>>> doing it
>>>>> in factor with a small twist - everything happening inside the
>>>> REPL.
>>>>> Makes it more fun and challenging (for me), although I don't
>> have
>>>> any
>>>>> code to show for it in the end.
>>>>>
>>>>> I'm trying to find the right tools for the job since there's a
>> lot
>>>> of
>>>>> words already available. Sometimes I reinvent something before I
>>>> find
>>>>> it, e.g. I wrote a last-n before finding last*.
>>>>>
>>>>> Would it be OK if I sometimes ask you for tips on what would be
>>>>> idiomatic/simpler/shorter/faster than what I have(n't) found?
>>>>>
>>>>> The first problem I really couldn't find is picking a maximum
>> from
>>>> a
>>>>> sequence based on a quotation pulling out the key. An example
>> will
>>>> say
>>>>> it the best I guess:
>>>>>
>>>>>> { { 1 2 } { 1 3 } { -1 4 } } [ second ] max-by .
>>>>>
>>>>> { -1 4 }
>>>>>
>>>>> Here is my definition:
>>>>>
>>>>> : max-by ( seq quot -- result ) [ unclip-slice ] dip '[ [ [ _
>> call
>>>> ] bi@
>>>>>> ] 2keep ? ] reduce ; inline
>>>>>
>>>>> Using fry for such a general word would be a bit of an overkill
>>>> but for
>>>>> demonstration purposes it's OK I guess.
>>>>>
>>>>> Is there no standard word that already does something similar?
>> Or
>>>> is
>>>>> there a way to write this with the existing sequence combinators
>>>> that
>>>>> it's so short there was no need to create this generic word?
>>>>>
>>>>> --
>>>>> ------------
>>>>> Peter Nagy
>>>>> ------------
>>>>>
>>>>> _______________________________________________
>>>>> Factor-talk mailing list
>>>>> Factor-talk@lists.sourceforge.net
>>>>> https://lists.sourceforge.net/lists/listinfo/factor-talk
>>>>
>>>> ---=====---
>>>> Александр
>>>>
>>>> _______________________________________________
>>>> Factor-talk mailing list
>>>> Factor-talk@lists.sourceforge.net
>>>> https://lists.sourceforge.net/lists/listinfo/factor-talk
>>> _______________________________________________
>>> Factor-talk mailing list
>>> Factor-talk@lists.sourceforge.net
>>> https://lists.sourceforge.net/lists/listinfo/factor-talk
>>
>> Jon, Alex, hi.
>>
>> Any reason why supremum-by and infimum-by are not on the "Searching
>> sequences" doc page? If you agree I can add these together with
>> supremum
>> and infimum.
>>
>> I'll take a look at map-reduce, thanks. I switched from using the
>> factor
>> IDE REPL to emacs with Fuel because today I kept creating an
>> infinite
>> loop and couldn't break it for the life of me in the IDE. In emacs
>> it
>> was C-c C-c. Since I couldn't break it I didn't even know it's an
>> infinite loop. That led me to open a file and save the definitions
>> for
>> debugging purposes, so I kind of broke my rules at this point. Oh
>> well,
>> at least I solved another "day" today, although I'm rather behind at
>> this point, not enough time.
>>
>> As far as roadblocks go, here is my solution to the 5th day. (react)
>> is
>> ugly with t/f, that's where I had the infinite loop and just quickly
>> hacked the solution in. It takes quite a while to run, showing
>> profile
>> output further down:
>>
>> USING: arrays io.encodings.utf8 io.files kernel math math.ranges
>> prettyprint
>> sequences ;
>>
>> IN: aoc
>> : reacts? ( a b -- ? ) - abs 32 = ;
>> : (react) ( seq -- seq ? ) dup [ last ] [ dup length 2 - swap nth ]
>> bi
>> reacts? [ 2 head* t ] [ f ] if ;
>> : has-2? ( seq -- ? ) length 2 >= ;
>> : react ( seq -- seq ) dup has-2? [ (react) [ react ] when ] when ;
>> : (flow) ( seq seq -- seq seq ) unclip-slice swap [ suffix! ] dip ;
>> : flow ( seq seq -- seq ) dup empty? [ drop ] [ (flow) [ react ] dip
>> flow ] if ;
>> : load5 ( -- str ) "5.txt" utf8 file-contents ;
>> : solve5 ( seq seq -- len ) flow length ;
>> : upper ( c -- c ) dup 96 > [ 32 - ] when ;
>> : nounit ( seq u -- seq ) [ [ upper ] dip = not ] curry filter ;
>> : do5-2 ( str u -- res ) [ nounit V{ } clone swap solve5 ] keep
>> 2array ;
>> : solve5-2 ( str -- res ) CHAR: A CHAR: Z [a,b] swap [ swap do5-2 ]
>> curry map [ first ] infimum-by ;
>>
>> ----
>>
>> IN: aoc V{ } clone load5
>>
>> --- Data stack:
>> V{ }
>> "bBCRGgrwgKknNGWnNWUuwHoeEtTOvEeVhYZzrZJjFfzNnpPHtTgGhNtTxBeEb..."
>> IN: aoc [ solve5 ] profile top-down profile.
>> depth   time ms  GC %  JIT %  FFI %   FT %
>> 15    4073.0   3.41   0.00   7.64   0.00 T{ thread f "Initial"
>> ~quotation~ ~quotation~ 17 ~box~ f t f H{...
>> 16    3821.0   0.60   0.00   1.99   0.00   react
>> 17    3818.0   0.60   0.00   1.99   0.00     (react)
>> 18    3811.0   0.60   0.00   1.99   0.00       subseq-unsafe-as
>> 19    1275.0   0.00   0.00   0.00   0.00         M\ array
>> nth-unsafe
>> 20     694.0   0.00   0.00   0.00   0.00           M\ fixnum
>> integer>fixnum
>> 19    1065.0   0.00   0.00   0.00   0.00         M\ array
>> set-nth-unsafe
>> 20     132.0   0.00   0.00   0.00   0.00           M\ fixnum
>> integer>fixnum
>> 19     579.0   0.00   0.00   0.00   0.00         +
>> 19     391.0   0.00   0.00   0.00   0.00         M\ growable
>> set-nth-unsafe
>> 20     155.0   0.00   0.00   0.00   0.00           M\ vector
>> underlying>>
>> 19     359.0   0.00   0.00   0.00   0.00         M\ growable
>> nth-unsafe
>> 20     169.0   0.00   0.00   0.00   0.00           M\ vector
>> underlying>>
>> 19      78.0  29.49   0.00  97.44   0.00         M\ vector
>> new-sequence
>> 20      77.0  29.87   0.00  98.70   0.00           <array>
>> 20       1.0   0.00   0.00   0.00   0.00           M\ fixnum
>> integer>fixnum
>> 19       1.0   0.00   0.00   0.00   0.00         -
>> 19       1.0   0.00   0.00   0.00   0.00         integer?
>> 18       3.0   0.00   0.00   0.00   0.00       M\ vector like
>> 18       1.0   0.00   0.00   0.00   0.00       head*
>> 19       1.0   0.00   0.00   0.00   0.00         -
>> 18       1.0   0.00   0.00   0.00   0.00       M\ sequence nth
>> 19       1.0   0.00   0.00   0.00   0.00         M\ integer
>> bounds-check?
>> 18       1.0   0.00   0.00   0.00   0.00       M\ growable
>> nth-unsafe
>> 19       1.0   0.00   0.00   0.00   0.00         M\ vector
>> underlying>>
>> 18       1.0   0.00   0.00   0.00   0.00       head
>> 17       1.0   0.00   0.00   0.00   0.00     has-2?
>> 17       1.0   0.00   0.00   0.00   0.00     >=
>> 16     251.0  46.22   0.00  93.63   0.00   (flow)
>> 17     240.0  48.33   0.00  97.92   0.00     push
>> 18     237.0  48.95   0.00  99.16   0.00       resize-array
>> 17       4.0   0.00   0.00   0.00   0.00     M\ string nth-unsafe
>> 18       2.0   0.00   0.00   0.00   0.00       M\ fixnum
>> integer>fixnum
>> 17       3.0   0.00   0.00   0.00   0.00     M\ virtual-sequence
>> nth-unsafe
>> 18       2.0   0.00   0.00   0.00   0.00       M\ slice virtual@
>> 19       1.0   0.00   0.00   0.00   0.00         +
>> 17       2.0   0.00   0.00   0.00   0.00     M\ slice length
>> 17       1.0   0.00   0.00   0.00   0.00     >
>> 17       1.0   0.00   0.00   0.00   0.00     integer?
>> 16       1.0   0.00   0.00   0.00   0.00   M\ slice length
>>
>> subseq-unsafe-as seems to be the culprit, which shows up in the
>> output
>> only when I use nth in (react), so I guess nth is being inlined and
>> I
>> don't see where is this call coming from. This is basically getting
>> the
>> second to last value from a vector, I couldn't find a simpler and
>> faster
>> solution. Maybe a clean array would have less overhead but I'd have
>> to
>> rewrite the algo and keep a "real length" or pointer into it which
>> might
>> slow the whole thing down again.
>>
>> So, is nth really that slow? :)
>>
>> Another thing that tricked me:
>>
>> IN: aoc V{ 1 2 3 } 2 head-slice* 3 suffix! >array .
>> { 1 }
>> IN: aoc V{ 1 2 3 } rest-slice 3 suffix! >array .
>> { 2 3 }
>>
>> Slices work differently than I expected :) Are there clojure-like
>> data
>> structures that are immutable and structurally share most of their
>> content?
>>
>> --
>> ------------
>> Peter Nagy
>> ------------
>>
>> _______________________________________________
>> Factor-talk mailing list
>> Factor-talk@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/factor-talk
> _______________________________________________
> Factor-talk mailing list
> Factor-talk@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/factor-talk


_______________________________________________
Factor-talk mailing list
Factor-talk@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/factor-talk

Reply via email to