1. 9
    1. 6

      I haven’t wanted to flood this lovely place with all my recent posts on jq, but I thought this short one might be of interest as it hopefully explains some subtleties of the comma as generator, and streaming.

    2. 3

      This is cool, writing a condition this way is unfamiliar to me but arguably very natural. A beginner mistake, in say Python, is to write thing == ("a" or "b") when you meant thing == "a" or thing == "b". It must happen by transliterating from English too closely: “it equals ‘a’ or ‘b’”. But in jq you can correctly write thing == ("a", "b") and everything distributes over the commas automatically.

      The choice operator in Verse is like this too:

      And I think Verse and jq do a similar cross product when both arguments are a generator, like (10, 20, 30) + (8, 9) gives you 6 results.

      1. 1

        Ooh thanks for the reminder about that Verse video, I’ve been meaning to watch it, but haven’t yet. This is the prompt I need.

    3. 2

      Very cool! I especially like how when you have multiple generators, jq backtracks and produces all combinations. (Leftmost varies fastest.) Look at this!

      # -n = --null-input
      # -c = --compact-output
      # objects
      jq -nc '{a: (1, 2), b: (10, 20)}' -c
      {"a":1,"b":10}
      {"a":1,"b":20}
      {"a":2,"b":10}
      {"a":2,"b":20}
      

      Generators inside arrays are flattened …

      jq -nc '[(10, 20), range(3)]'
      [10, 20, 0, 1, 2]
      

      … but variables bind one value at a time, and you can use that to produce arrays. This also demonstrates that the generator backtracking happens across pipes.

      jq -nc '(1, 2) as $a | (10, 20) as $b | [$a, $b]'
      [1,10]
      [1,20]
      [2,10]
      [2,20]
      # Or use this: jq -c -n '[[0, 1], [3, 4]] | combinations' 
      

      Funnily enough: when I use string concatenation, the output varies leftmost-fastest instead!

      jq -nc '("0", "1") + ("0", "1")'
      "00"
      "10"
      "01"
      "11"
      
      1. 2

        Funnily enough: when I use string concatenation, the output varies leftmost-fastest instead!

        Huh, interesting. It looks like it evaluates arguments right-to-left, so maybe that’s why?

        $ jq -nc '(0 + "left") + (1 + "right")'
        jq: error (at <unknown>): number (1) and string ("right") cannot be added
        

        If it evaluates the right-hand generator first, then it makes sense that the right-hand would end up being the outer loop.

      2. 1

        Wow, lots to explore there, thank you for sharing! I’m still trying to get used to thinking in terms of jq’s generators and streaming in general. This will provide food for thought.

      3. 1

        Does jq have pattern matching?

        And can you turn arrays into generators?

        I want to see how Prologgy things can get. Ultimately not very, I know, because backtracking and unification are only two parts of Prolog; the third part is its efficient inference algorithm. Nevertheless.

        For example, somethings like this would be fun to cook up. Please forgive syntax mistakes, I am not fluent in jq.

        def siblings(parentage):
          generator(parentage) as $var1
          | generator(parentage) as $var2
          | select( (var1.parent == var2.parent) and (var1.kid != var2.kid) )
          | [var1.kid, var2.kid]
        
        [{parent: "Ann", kid: "Bob"},
         {parent: "Ann", kid: "Che"},
         {parent: "Don", kid: "Eve"},
         {parent: "Don", kid: "Fay"}] as $x
        | siblings(x)
        
        # desired output [["Bob", "Che"], ["Eve", "Fay"]]