将 clist 从属性列表传递给命令

将 clist 从属性列表传递给命令

我有一个命令,它接受逗号分隔的列表并对其进行处理。我想使用expl3属性列表存储一组这样的列表。这是问题的简单版本。我的基本命令可以工作,但是当我尝试使用从属性列表中检索到的列表时,它会挂起,我不明白为什么。(取消注释命令\mylist中的调用\fromprop以查看问题。

\documentclass{article}
\ExplSyntaxOn
\clist_new:N \l_mylist_clist
\NewDocumentCommand{\mylist}{m}{
    \clist_set:Nn \l_mylist_clist {#1}
    \int_step_inline:nn {4}{
    \clist_pop:NN \l_mylist_clist \l_tmpa_tl 
    \l_tmpa_tl\par
    }}
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
    A =  {1,2,3,4},
    B =  {1,1,2,2},
    C =  {1,1,1,1}
}
\NewDocumentCommand{\fromprop}{m}{
    \prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
    \l_tmpb_tl
%   \mylist{\l_tmpb_tl}
    }
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}

答案1

您要尝试将其涂抹\mylist到瓶子上,而不是涂抹到里面的酒上。

使用代码的复杂命令expl3应该在“用户级别”和“程序员级别”之间划分。

因此,您可以生成适合程序员级别函数的变体。

\documentclass{article}

\ExplSyntaxOn

\clist_new:N \l_mylist_clist
\prop_new:N \l_myprop_prop

\prop_set_from_keyval:Nn \l_myprop_prop {
    A =  {1,2,3,4},
    B =  {1,1,2,2},
    C =  {1,1,1,1}
}

\NewDocumentCommand{\mylist}{m}
  {
    \alan_mylist:n { #1 }
  }

\cs_new_protected:Nn \alan_mylist:n
  {
    \clist_set:Nn \l_mylist_clist {#1}
    \int_step_inline:nn {4}
      {
        \clist_pop:NN \l_mylist_clist \l_tmpa_tl 
        \l_tmpa_tl\par
      }
  }
\cs_generate_variant:Nn \alan_mylist:n { V }

\NewDocumentCommand{\fromprop}{m}
  {
    \prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
    \alan_mylist:V \l_tmpb_tl
  }

\ExplSyntaxOff

\begin{document}

\mylist{1,2,3,4}

\fromprop{A}

\end{document}

在此处输入图片描述

答案2

您可以看到此测试文档中存在的问题:

\documentclass{article}
\ExplSyntaxOn
\clist_new:N \l_mylist_clist
\NewDocumentCommand{\mylist}{m}{
    \clist_set:Nn \l_mylist_clist {#1}
    \show \l_mylist_clist % <---- HERE
    \int_step_inline:nn {4}{
    \clist_pop:NN \l_mylist_clist \l_tmpa_tl
    \show \l_tmpa_tl % <---- HERE
    \l_tmpa_tl\par
    }}
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
    A =  {1,2,3,4},
    B =  {1,1,2,2},
    C =  {1,1,1,1}
}
\NewDocumentCommand{\fromprop}{m}{
    \prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
    \l_tmpb_tl
    \mylist{\l_tmpb_tl}
    }
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}

输出结果如下:

> \l_mylist_clist=macro:
->1,2,3,4.

> \l_tmpa_tl=macro:
->1.

[...]

> \l_mylist_clist=macro:
->\l_tmpb_tl .

> \l_tmpa_tl=macro:
->\l_tmpb_tl .

> \l_tmpa_tl=macro:
->\q_no_value .

这里的问题是,你将 a 设置clist为包含 的单个元素\l_tmpb_tl。如果你弹出 1 个元素clist4 次,你最终会得到一个空值,在 expl3 中由 quark 表示\q_no_value。然后,你排版这个 quark,它会尝试扩展它,导致无限循环。来自文档:

Quark 是控制序列(实际上是标记列表),它们会自行扩展,因此永远不应在代码中直接执行。这会导致无限循环!

为了修复这个问题,我建议这样做:

\documentclass{article}
\ExplSyntaxOn
\cs_new_protected:Nn \mylist_helper:n {
    \clist_map_inline:nn { #1 } {
        ##1\par
    }
}
\cs_set_eq:NN \mylist \mylist_helper:n
\cs_generate_variant:Nn \mylist_helper:n { V }

\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
    A =  {1,2,3,4},
    B =  {1,1,2,2},
    C =  {1,1,1,1}
}

\NewDocumentCommand{\fromprop}{m}{
    \prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
    \l_tmpb_tl
    \mylist_helper:V \l_tmpb_tl
    }
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}

在这里,我们正确地扩展了中的变量,并且通过使用内置迭代器\fromprop避免意外超出的末尾。clist


编辑

谢谢,但这并没有捕捉到我需要保留的代码的一个基本属性,特别是宏\mylist本身,它(出于与此无关的原因)不能仅通过简单的映射函数来实现。那么有没有一种解决方案可以保持\mylist 完整并满足我的要求?

因此,我正在寻找一种方法,使输出的行为\fromprop与我直接输入列表的行为完全一样。

一个最小改变的解决方案:

\documentclass{article}
\ExplSyntaxOn
\clist_new:N \l_mylist_clist
\NewDocumentCommand{\mylist}{m}{
    \clist_set:Nn \l_mylist_clist {#1}
    \int_step_inline:nn {4}{
    \clist_pop:NN \l_mylist_clist \l_tmpa_tl
    \quark_if_no_value:NF \l_tmpa_tl { % <--- CHANGED
        \l_tmpa_tl\par
    }
    }}
\prop_new:N \l_myprop_prop
\prop_set_from_keyval:Nn \l_myprop_prop {
    A =  {1,2,3,4},
    B =  {1,1,2,2},
    C =  {1,1,1,1}
}
\NewDocumentCommand{\fromprop}{m}{
    \prop_get:NnN \l_myprop_prop {#1} \l_tmpb_tl
    \l_tmpb_tl
    \exp_args:NV \mylist \l_tmpb_tl % <--- CHANGED
    }
\ExplSyntaxOff
\begin{document}
\mylist{1,2,3,4}
\fromprop{A}
\end{document}

此解决方案用于在 之前\exp_args:NV扩展 的值。它还用于防止在到达列表末尾时意外扩展 quark(这部分不是绝对必要的,但这可能是一个好主意)。\l_tmpb_tl\mylist\quark_if_no_value:NF

相关内容