1

To gain a better understanding of macros, expansion and tex-core in general, I tried to implement foldr like this:

\long\def\cons#1#2{%
  \def\tmp{#2}%
  \ifx\tmp\nil%
    [#1,[]]%
  \else
    \consI{#1}#2%
  \fi
}%
\long\def\consI #1[#2]{%
  [#1,#2]%
}%
\def\nil{[]}%
\long\def\foldr(λ#1,#2->#3)#4[#5]{%
  \def\tempitem{#5}%
  \ifx\tempitem\nil%
    \def\next{#4}%
  \else
    \def\next{%
      \foldrI(λ#1,#2->#3)<#4>#5 %
    }%
  \fi
  \next
}%
\long\def\foldrI(λ#1,#2->#3)<#4>#5,#6{%
  \def#1{#5}%
  \def#2{\foldr(λ#1,#2->#3)#4[#6]}%
  #3 %
}%

\cons{4}{[3,[]]}\par
\foldr(λ\x,\acc->\cons\x\acc){\nil}[h,e,l,l,o,[]]\par
\end

cons seems to work fine; However, foldr ends up with this error:

Runaway argument?
{\x }\acc \fi  ,l,o,, ]\par \end 
! File ended while scanning use of \consI.
<inserted text> 
                \par 

I am unsure where this is coming from; I am also unsure where the \fi is coming from in the error message.

To clear things up: i want empty lists to be [[]], [a,[]] would be a one element list. The invocation of the foldr function at the end of the file should produce the exact same list that it was given as an argument.

I tried to keep the definition roughly similar to this implementation of an "element based loop"

\def\listingloopENDMARKER{\par \listingloopENDMARKER}
\long\def\listingloop#1in#2#3{%
  \looppicker{#1}{#3}#2,\listingloopENDMARKER,%
}%
\long\def\looppicker#1#2#3,{%
  \def\tempitem{#3}%
  \ifx\tempitem\listingloopENDMARKER
    \let\next=\relax%
  \else
    \def#1{#3}%
    #2%
    \def\next{\looppicker{#1}{#2}}%
  \fi
  \next
}%
\listingloop\x in{a,b,c,,d,e}{%
  The current item is ‘\x’
}

Maybe there is something wrong with the syntax I want the command to have?

Note that I am aware that this could probably more sensibly be done with latex3 and the sequence data structure; I am interested in solving it using tex only.

EDIT

(code exaples given in haskell notation)

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f initial b = b
foldr f initial (a:t) = f a (foldr f initial t)

so it is a function that takes a function as an argument, walks over the given list. it basically provides the given function f with an element of the list and an accumulating value acc (starting out as initial).

examples:

foldr (+) 0 [1,2,3] == 0+3+2+1
foldr (\x acc -> cons x acc) [] [1,2,3] == [1,2,3]
foldr (\x acc -> cons (x+1) acc) [] [1,2,3] == map (+1) [1,2,3] == [2,3,4]
foldr (\x acc -> "_" ++ x ++ acc) "" ["hi","this","is"] == "_hi_this_is"
3
  • 1
    Your first \ifx compares { with the first token in #2 (after argument replacement), so it will usually return false. It would help if you describe what \foldr is supposed to do. Another problem is that your macros don't work by pure expansion, so they won't behave in \message.
    – egreg
    Commented Oct 27, 2021 at 11:08
  • @egreg I updated the question with a description of foldr and changed the \ifx part to something (hopefully better); I am still unsure when {} groups characters to one single parameter and when they are just plain characters. (maybe I understood that wrong in the first place) Commented Oct 27, 2021 at 11:30
  • 3
    You could look at the implementation of fold in plain tex in lambda.sty ctan.org/tex-archive/macros/generic/lambda-lists?lang=en Commented Oct 27, 2021 at 11:45

1 Answer 1

3

in

\foldr(λ\x,\acc->\cons\x\acc){\nil}[h,e,l,l,o,[]]

#5 is h,e,l,l,o,[ (terminating at the first ])

You would need

 \foldr(λ\x,\acc->\cons\x\acc){\nil}[{h,e,l,l,o,[]}]

But as you will always need brace groups to guard nested [] it may be better to use a different syntax that uses {..} rather than [...] for list construction.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .