用ABAP模拟JavaScript的柯里化语言特性(Curry)
As I mentioned in What should an ABAPer continue to learn as an application developer, function programming language is a mind -blower to ABAPers who have got used to ABAP as an imperative programming language.
One of important concept in functional programming is Currying.
Currying intensively manipulates functions.
The name “Currying”, coined by Christopher Strachey in 1967, is a reference to logician Haskell Curry. Although the concept defined in wikipedia looks a little bit obscure, in fact every one should have already learned it during his / her high school in mathematics class.
Still remember how you resolve this equation below? During the process, you are actually applying the Curry idea!
Let’s now see some real example in code.
<script type="text/javascript">
function jerryPrint(person, ...arg){
console.log(person + " can program with: " + arg);
}
jerryPrint("Jerry", "Java", "JavaScript", "Scala", "C++");
</script>
No doubt we can get the following output:
Now use Curry concept.
(1) in line 3, I define a Curry function as a factory, which will return a NEW function with bound argument passed in Curry call.
(2) in line 9, I get a new curried function curriedPrint with a default programming language ABAP. It means from now on I can call this new function without passing ABAP as argument any more.
(3) In line 11 I call this new function by specifying other languages. and finally in output ABAP are still included:
A typical advantage of Curry is, it is now possible to develop a couple of small but REUSABLE functions with fine granularity and fulfill complex requirement by constructing them via Curry. See this example which will generate output: jerry-abap
The conversion task is not done via the idea of functional programming: it simply leverages the built-in method provided by String and Array.
See how it could be rewritten in a PURE functional programming way using Curry: Among lines 8 ~ 11, four dedicated functions are defined and each one has its single responsibility. Finally a new conversion function is composited in line 13, this process is called function composition.
Output in console: jerry-java
Curry in ABAP
Now let’s see how to implement the first language print example in ABAP using Curry. Always keep in mind the idea of Curry: suppose I have a function with m numbers of arguments.
I construct a new function bound with a set of say n numbers of argument passed during Curry process, and after that I can just call the new curried function with ( m – n ) numbers of argument.
Let’s first see what can be achieved in ABAP. I have a simple print function module ZJERRY_PRINT in ABAP with 3 optional importing parameters:
Its implementation is simple:
WRITE: / 'Jerry can program with the following: ' COLOR COL_GROUP.
IF iv_first IS SUPPLIED.
WRITE: / iv_first COLOR COL_NEGATIVE.
ENDIF.
IF iv_second IS SUPPLIED.
WRITE: / iv_second COLOR COL_HEADING.
ENDIF.
IF iv_third IS SUPPLIED.
WRITE: / iv_third COLOR COL_POSITIVE.
ENDIF.
And this function module can simply be curried via factory method ZCL_CURRY by passing name of original function module plug bound argument value.
Test output
In the first time, when I call first curried function module, although I didn’t explicitly specify the first argument with value ABAP, still it appears in the result output, since the value of this argument is already bound to the “context” of curried function module when it is constructed.
The same rule holds for the second round test, where I bind two arguments to the second curried function module.
How it is implemented in ABAP?
Where in JavaScript, a curried function can simply be created together with bound argument passed by consumer just WITHIN A SINGLE LINE,
actually what you see is just a tip of the iceberg. Take V8 JavaScript engine in Chrome for example, the implementation of bind behind the scene is really tremendous. And my ABAP implementation consists of three steps.
Step1: parse the signature of function module to be curried, to prepare the dynamical generation of curried function module in next step.
Step2: technically speaking the curried function module has the same signature as the original function module, so just generate it dynamically by making use of signature parsed from first step.
Step3: source code post adaptation. This post activity consists of two further steps.
(1) For those parameters which already have bound value passed in during curry call, use the bound one instead.
(2) Populate source code which will internally delegate the call to the original function module.
Below is the source code of curried function module for original function ZJERRY_PRINT with first argument bound with value ‘ABAP’:
FUNCTION zcurry20170226043103.
*"--------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(IV_FIRST) TYPE STRING OPTIONAL
*" REFERENCE(IV_SECOND) TYPE STRING OPTIONAL
*" REFERENCE(IV_THIRD) TYPE STRING OPTIONAL
*"--------------------------------------------------------------------
DATA: lt_ptab TYPE abap_func_parmbind_tab.
DATA: ls_para LIKE LINE OF lt_ptab.
DATA: _iv_first LIKE iv_first.
_iv_first = 'ABAP'.
ls_para = VALUE #( name = 'IV_FIRST' kind = abap_func_exporting value = REF #( _iv_first ) ).
APPEND ls_para TO lt_ptab.
DATA: _iv_second LIKE iv_second.
_iv_second = iv_second.
ls_para = VALUE #( name = 'IV_SECOND' kind = abap_func_exporting value = REF #( _iv_second ) ).
APPEND ls_para TO lt_ptab.
DATA: _iv_third LIKE iv_third.
_iv_third = iv_third.
ls_para = VALUE #( name = 'IV_THIRD' kind = abap_func_exporting value = REF #( _iv_third ) ).
APPEND ls_para TO lt_ptab.
TRY.
CALL FUNCTION 'ZJERRY_PRINT' PARAMETER-TABLE lt_ptab.
CATCH cx_root INTO DATA(cx_root).
WRITE: / cx_root->get_text( ).
ENDTRY.
ENDFUNCTION.
Finally ZCL_CURRY provides a method CLEANUP to delete those automatically generated function module.
Hope this little prototype can help ABAPers to have a basic understanding about Curry concept in functional programming world.
Further reading
I have written a series of blogs which compare the language feature among ABAP, JavaScript and Java. You can find a list of them below:
- Lazy Loading, Singleton and Bridge design pattern in JavaScript and in ABAP
- Functional programming – Simulate Curry in ABAP
- Functional Programming – Try Reduce in JavaScript and in ABAP
- Simulate Mockito in ABAP
- A simulation of Java Spring dependency injection annotation @Inject in ABAP
- Singleton bypass – ABAP and Java
- Weak reference in ABAP and Java
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 基于桶子法实现的两种排序算法
- Notes | 微观经济学课堂笔记(一)
- 将终结点图添加到你的ASP.NET Core应用程序中
- Stata | 爬取 CFPS 文献传送门并制作成 Markdown
- 委托的好处
- Elasticsearch安装和配置
- Notes | QUAIDS 模型
- Stata | 520,听说你也想快点找到...
- Stata | 批量替换变量值的小技巧
- 手把手教你完成课设作业使用Pandas对海平面温度异常进行分析,小白也能看的懂
- 谈谈自学 Stata 的体会
- Latex修改字体字号的大小
- Notes | GitHub Upload Large Files
- PPT 中插入图片的几个小技巧
- Stata | 整理调查问卷修改内容清单