english correction 3

This commit is contained in:
2024-09-25 11:15:42 +09:00
parent d7928d0934
commit 6de3b8f60e

View File

@@ -276,9 +276,9 @@
\end{figure}
Listing \ref{lst:filterbank_good} shows an example of a higher-order function \\ \texttt{filterbank} that takes another function \texttt{filter} that takes an input and a frequency as an argument, duplicates \texttt{n} of filter, and adds them together. Note that in the previous specification of mimium in \cite{matsuura2021a}, the binding of new variable and destructive assignment were the same syntax (\texttt{x = a}) but the syntax for the variable binding has changed to use \texttt{let} keyword. Also, because the semantics is call-by-value paradigm, reassignment syntax never be used in the current implementation.
Listing \ref{lst:filterbank_good} shows an example of a higher-order function \texttt{filterbank}, which takes another function \texttt{filter}—accepting an input and a frequency as arguments—duplicates \texttt{n} instances of \texttt{filter}, and adds them together. Note that in the previous specification of mimium \cite{matsuura2021a}, the syntax for variable binding and destructive assignment was the same (\texttt{x = a}). However, in the current syntax, variable binding now uses the \texttt{let} keyword. Additionally, since the semantics follow a call-by-value paradigm, reassignment syntax is no longer used in the current implementation.
The previous mimium compiler could not compile code that takes a function containing such a state as an argument because the tree of all internal states was statically determined at compile time, but the VM in the \lambdammm\ can manage it dynamically. Listing \ref{lst:bytecode_filterbank} shows translated VM instruction of the code. Recursive calls of the first line of code in \texttt{filterbank} and the functions given as arguments or obtained via upvalue like \texttt{filter} are called with the \texttt{CALLCLS} instruction instead of the \texttt{CALL} instruction. The \texttt{GETSTATE} and \texttt{SETSTATE} instructions are not used in this function because the internal state storage is switched when the \texttt{CALLCLS} is interpreted.
The previous mimium compiler was unable to compile code that took a function with an internal state as an argument because the entire tree of internal states had to be statically determined at compile time. However, the VM in \lambdammm\ can manage this dynamically. Listing \ref{lst:bytecode_filterbank} shows the translated VM instructions for this code. Recursive calls on the first line of \texttt{filterbank}, as well as calls to functions passed as arguments or obtained through upvalues (like \texttt{filter}), are executed using the \texttt{CALLCLS} instruction rather than the \texttt{CALL} instruction. The \texttt{GETSTATE} and \texttt{SETSTATE} instructions are not used in this function, as the internal state storage is switched dynamically when the \texttt{CALLCLS} instruction is interpreted.
\begin{lstlisting}[float,floatplacement=H,label=lst:filterbank_good,language=Rust,caption=\it Example code that duplicates filter parametrically using a recursive function and closure.]
fn filterbank(n,filter){
@@ -343,11 +343,14 @@
\section{Discussion}
\label{sec:discussion}
As seen in the example of the filterbank, in \lambdammm, signal graph can be parametrically generated in an evaluation of global context, compared to that Faust uses a term-rewriting macro and Kronos uses a type-level computation as in the Table \ref{tab:comparison}.
Heres the revised version of the text, ensuring that all references inside curly brackets remain unchanged:
As demonstrated in the example of the filterbank, in \lambdammm, a signal graph can be parametrically generated during the evaluation of the global context, whereas Faust uses a term-rewriting macro and Kronos employs type-level computation, as shown in Table \ref{tab:comparison}.
The ability to describe both the generation of parametric signal processing and its content in a single semantics will make it easier for novice users to understand the mechanism of the language. Also, the single semantics may facilitate run-time interoperation with other general-purpose languages.
The ability to describe both the generation of parametric signal processing and its execution content within a single semantics makes it easier for novice users to grasp the mechanics of the language. Additionally, having a unified semantics may simplify run-time interoperability with other general-purpose languages.
On the other hand, there is the problem that the single semantics causes \lambdammm\ to behave differently from the behavior expected in a normal lambda calculus.
However, there is a drawback: the unified semantics can cause \lambdammm\ to deviate from the behavior typically expected in standard lambda calculus.
\begin{table}[ht]
\centering
@@ -363,14 +366,16 @@
\subsection{Different Behaviour Depending on the Location of Let Binding}
\label{sec:letbinding}
By having functions that have internal states which change over time in mimium, when higher-order functions are used, there is a counterintuitive behavior compared to general functional programming languages.
Listing \ref{lst:filterbank_bad} is an example of the incorrect code slightly modified from the filterbank example in Listing \ref{lst:filterbank_good}. The difference between Listing \ref{lst:filterbank_good} and Listing \ref{lst:filterbank_bad} is that the recursive calls in the filterbank function are written directly, or once bound with \texttt{let} expression out of the inner function. Similarly, in the \texttt{dsp} function that will be called by the audio driver in mimium, the difference is whether the filterbank function is executed inside \texttt{dsp} or bound with \texttt{let} once in the global context.
In the case of normal functional language, if all the functions used in a composition do not contain destructive assignments, the calculation process will not change even if the variable bound by \texttt{let} were manually replaced with its term (beta reduction), as in the conversion from Listing \ref{lst:filterbank_good} to Listing \ref{lst:filterbank_bad}.
But in mimium, there are two major stages of evaluation, 0: the code is evaluated in the global environment (concretizing the signal processing graph) at first, and 1: the dsp function is repeatedly executed (actual signal processing) and the function may involve implicit internal state updates. Therefore, even though the code does not include destructive assignments, the recursive execution of the \texttt{filterbank} function is performed only once in Listing \ref{lst:filterbank_good} for the evaluation of the global environment, whereas in Listing \ref{lst:filterbank_bad}, every sample the dsp function is executed, the recursive function is executed and a closure is generated. Since the initialization of the internal state in the closure is performed at the time of closure allocation, in the example of Listing\ref{lst:filterbank_bad}, the internal state of the closure after the evaluation of \texttt{filterbank} is reset at each time step.
By using functions with internal states that change over time in mimium, there is a counterintuitive behavior when higher-order functions are used, compared to general functional programming languages.
Listing \ref{lst:filterbank_bad} presents an example of incorrect code, slightly modified from the filterbank example in Listing \ref{lst:filterbank_good}. The main difference between Listing \ref{lst:filterbank_bad} and Listing \ref{lst:filterbank_good} is whether the recursive calls in the \texttt{filterbank} function are written directly or are bound using a \texttt{let} expression outside of the inner function. Similarly, in the \texttt{dsp} function, which is called by the audio driver in mimium, the difference lies in whether the \texttt{filterbank} function is executed within \texttt{dsp} or bound with \texttt{let} once in the global context.
In a typical functional programming language, as long as none of the functions in the composition involve destructive assignments, the calculation process remains unchanged even if the variable bound by \texttt{let} is replaced with its term (via beta reduction), as seen in the transformation from Listing \ref{lst:filterbank_bad} to Listing \ref{lst:filterbank_good}.
However, in mimium, there are two distinct stages of evaluation. 0: The code is first evaluated in the global environment (where the signal processing graph is concretized). 1: The \texttt{dsp} function is executed repeatedly (handling actual signal processing), and may involve implicit updates to internal states.
Even though the code contains no destructive assignments, the recursive execution of the \texttt{filterbank} function occurs only once in Listing \ref{lst:filterbank_good}, during the global environment evaluation. In contrast, in Listing \ref{lst:filterbank_bad}, the recursive function is executed and a closure is generated each time the \texttt{dsp} function runs on every sample. Since the internal state of the closure is initialized at the time of closure allocation, in the example of Listing \ref{lst:filterbank_bad}, the internal state of the closure is reset at each time step following the evaluation of \texttt{filterbank}.
\begin{lstlisting}[float,floatplacement=H,label=lst:filterbank_bad,language=Rust,caption=\it Wrong example of the code that duplicate filter parametrically.]
fn bandpass(x,freq){
@@ -404,26 +409,26 @@
}
\end{lstlisting}
This means that the major compiler optimization techniques such as the constant folding and the function inlining can not simply be appropriated for mimium. Those optimizations should be done after the evaluation of a global context and before evaluating \texttt{dsp} function.
This implies that major compiler optimization techniques, such as constant folding and function inlining, cannot be directly applied to mimium. These optimizations must be performed after the global context evaluation and before the evaluation of the \texttt{dsp} function.
To address this issue, it would be necessary to introduce a distinction in the type system to indicate whether a term should be used during the global context evaluation (stage 0) or during actual signal processing (stage 1). This can be achieved with Multi-Stage Computation \cite{Taha1997}. Listing \ref{lst:filterbank_multi} provides an example of the \texttt{filterbank} code using BER MetaOCamls syntax: \texttt{.<term>.}, which generates a program to be used in the next stage, and \texttt{\textasciitilde term}, which embeds terms evaluated in the previous stage \cite{kiselyov2014a}.
To solve this situation, introducing distinction whether the term should be used in global context evaluation (stage 0) and in the actual signal processing (stage 1) in type system. This can be realized with Multi-Stage Computation\cite{Taha1997}. Listing \ref{lst:filterbank_multi} is the example of \texttt{filterbank} code using BER MetaOCaml's syntaxes \texttt{.<term>.} which will generate evaluated program to be used in a next stage, and \texttt{\textasciitilde term} which embed terms evaluated at the previous stage\cite{kiselyov2014a}.
\texttt{filterbank} function is evaluated in stage 0 while embedding itself by using \texttt{\textasciitilde}. This multi-stage computation code still has a same semantics in a generative signal graph generation and execution of the signal processing, in contrast to that Faust and Kronos.
The \texttt{filterbank} function is evaluated in stage 0 while embedding itself with \texttt{\textasciitilde}. This multi-stage computation code retains the same semantics for both the generation of the signal processing graph and the execution of the signal processing, in contrast to Faust and Kronos.
\subsection{A Possibility of the Foreign Stateful Function Call}
The data structure of closure in \lambdammm\ is a combination of functions and internal states, as shown in Figure 3. The fact that\\ \texttt{filterbank} samples do not require any special handling of internal states also means that external signal processor (Unit Generator: UGen) such as oscillators and filters written in C or C++, for example, can be called from mimium in the same way as normal closure calls, and it is even possible to parametrically duplicate and combine external UGens. This is an advantage that is difficult to implement in Faust and other similar languages, but easy to implement on \lambdammm\ paradigm.
However currently, mimium is based on sample-by-sample processing and cannot handle buffer-by-buffer value passing. Since most native unit generators perform processing on a buffer-by-buffer basis, there are not many cases where external UGens are utilized in practice for now. However, in the \lambdammm, only $feed$ terms need to be processed sample-by-sample, so it is possible to distinguish functions that can only process one sample at a time from functions that can process concurrently at the type level. As the Multi-rate specification is being considered in Faust\cite{jouvelotDependentVectorTypes2011}, it may be possible to read/write buffer between an external Unit Generator by having the compiler automatically determine the parts that can be processed as buffer-by-buffer.
The closure data structure in \lambdammm\ combines functions with internal states, as shown in Figure 3. The fact that \texttt{filterbank} samples do not require special handling for internal states means that external signal processors (Unit Generators: UGens), such as oscillators and filters written in C or C++, can be called from mimium just like normal closure calls. Additionally, it is possible to parametrize, duplicate, and combine external UGens. This capability is difficult to implement in Faust and similar languages but is easily achievable in the \lambdammm\ paradigm.
However, mimium currently uses sample-by-sample processing and cannot handle buffer-by-buffer value passing. Since most native unit generators process data on a buffer-by-buffer basis, there are not many practical cases where external UGens are used at this time. Nonetheless, in \lambdammm, only $feed$ terms require sample-by-sample processing. It is therefore possible to differentiate functions that can only process one sample at a time from those that can process concurrently at the type level. As the multi-rate specification is being considered in Faust \cite{jouvelotDependentVectorTypes2011}, it may be possible to facilitate buffer-based processing between an external Unit Generator by having the compiler automatically determine which parts can be processed buffer-by-buffer.
\section{Conclusion}
\label{sec:conclusion}
This paper proposed \lambdammm , an intermediate representation for the programming languages for music and signal processing with the virtual machine and instruction set to run it. \lambdammm\ enables to describe generative signal graph and its contents in a single syntax and semantics. However, user have to be responsible to write codes that does not create escapable closures during the iterative execution of DSP, which will be difficult to understand for novice users.
In this paper, the translation from \lambdammm\ terms from VM instructions is explained by just showing examples of the code and its expected result of instructions as well as the semantics of VM is presented with pseudo-code of the behaviour. More formal semantics and translation process should be considered along with an introduction of the multi-stage computation.
I hope that this research will lead to more general representations of music and sound on the digital computer and more connections between the theory of languages for music and more general programming language theory.
This paper proposed \lambdammm, an intermediate representation for programming languages for music and signal processing, along with a virtual machine and instruction set to execute it. \lambdammm\ enables the description of generative signal graphs and their contents within a unified syntax and semantics. However, users are responsible for ensuring that their code does not create escapable closures during the iterative execution of DSP, which can be challenging for novice users to grasp.
In this paper, the translation of \lambdammm\ terms into VM instructions was illustrated by showing examples of code and the corresponding expected bytecode, alongside pseudo-code to describe the behavior of the VM. More formal semantics and a detailed translation process should be considered, especially with the introduction of multi-stage computation.
I hope that this research will contribute to more general representations of music and sound on digital computers and foster deeper connections between the theory of languages for music and the broader field of programming language theory.
\section{Acknowledgments}