In computer coding, it's super important to write really good code. Good code doesn't just make programs run faster, it also helps developers work better. But figuring out what makes code good can be tricky, and it's not just about making things run quickly.
Good code has things like being easy to test, easy to keep up, easy to use again, and easy to add more stuff to. These things are like measuring sticks for how tough and reliable the code is. But knowing how to make code like that isn't always clear, so we look into ways to help us write clean code.
One cool way to do this is by using functional programming. It's a style of coding inspired by math, and it's all about using expressions and putting functions together. We separate pure functions, which only do one thing and don't mess with anything else, from impure ones, which do more things. This helps make our code not just easy to understand but also makes testing and modifying way simpler.
In ABAP (a programming language), Object-Oriented ABAP is a great way to use functional programming ideas. It's not a perfect solution for everything, but it really helps us think about problems in new ways.
even :: (Integral a) => a -> Bool even x | x `mod` 2 == 0 = True | otherwise = False
Here, I've defined a function called even that takes an integral value, x, and returns a boolean indicating whether x is even. I've used guards (|) to make the code concise and expressive which is the main characteristic of functional programming.
odd :: (Integral a) => a -> Bool odd = not . even
In this example, I leverage the composition operator (.) to define the odd function succinctly. I take advantage of the previously defined even function, showcasing the power of composing functions to create new ones.
filter :: (a -> Bool) -> [a] -> [a] filter _ [] = [] filter pred (x:xs) | pred x = x : filter pred xs | otherwise = filter pred xs
The filter function showcases a common higher-order function in functional programming. I take a predicate function,, and a list of any type [a], returning a new list containing only the elements that satisfy the predicate. This serves as a clear example of functional programming’s emphasis on using higher-order functions for concise and expressive code.
In this function, I highlight the recursive technique — a fundamental aspect of functional programming. Recursion is not only a technical approach but also a distinctive way of thinking. Embracing recursion allows me to break down complex problems into simpler, more manageable sub-problems, fostering code elegance and a deeper understanding of functional programming principles.
ghci> filter odd [1..100] [1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,67,69,71,73,75,77,79,81,83,85,87,89,91,93,95,97,99] ghci> filter even [1..100] [2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72,74,76,78,80,82,84,86,88,90,92,94,96,98,100]
These examples demonstrate Haskell’s functional programming features, emphasizing the concise and declarative nature of the code. The use of higher-order functions, immutability, and function composition contributes to the readability and maintainability of the codebase. These principles form the basis for our exploration of functional programming in Object-Oriented ABAP in the subsequent sections.
Translating Functional Programming Concepts: Haskell to ABAP
Let’s seamlessly translate the Haskell code above into ABAP, aiming for a natural adaptation that captures the essence of functional programming concepts applied in an Object-Oriented (OO) paradigm, specifically within the ABAP language.
Here is the code implementation,
ABAP
INTERFACE zif_predicate PUBLIC . METHODS evaluate IMPORTING value TYPE any RETURNING VALUE(result) TYPE abap_bool. ENDINTERFACE.
The zif_predicate interface serves as a contract or blueprint for classes that implement a specific method signature, in this case, the evaluate method. I've defined it to establish a common contract that the zcl_predicate_even and zcl_predicate_odd classes adhere to.
The purpose of this interface is to declare a method, evaluate, that takes a value and returns a boolean result. Its usage lies in ensuring that all classes implementing this interface adhere to a consistent contract. In this context, I use the interface to implement a higher-order function through the application of dependency injection.
Even Predicate in Haskell vs ABAP
Haskell
even :: (Integral a) => a -> Bool even x | x `mod` 2 == 0 = True | otherwise = False
ABAP
CLASS zcl_predicate_even DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES zif_predicate. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_predicate_even IMPLEMENTATION. METHOD zif_predicate~evaluate. FIELD-SYMBOLS <value> TYPE i. ASSIGN value TO <value>. result = COND #( WHEN <value> MOD 2 = 0 THEN abap_true ELSE abap_false ). ENDMETHOD. ENDCLASS.
In both languages, I've defined a predicate to check if a number is even. The ABAP implementation uses an interface zif_predicate to establish a common contract and the evaluate method mirrors the Haskell logic. Additionally, I exemplify the application of dynamic programming in ABAP to adeptly handle generic data types, which is common in the functional programming world.
Odd Predicate in Haskell vs ABAP
Haskell
odd :: (Integral a) => a -> Bool odd = not . even
ABAP
CLASS zcl_predicate_odd DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES zif_predicate. PROTECTED SECTION. PRIVATE SECTION. METHODS negate IMPORTING truth TYPE abap_bool RETURNING VALUE(result) TYPE abap_bool. ENDCLASS. CLASS zcl_predicate_odd IMPLEMENTATION. METHOD zif_predicate~evaluate. result = negate( CAST zif_predicate( NEW zcl_predicate_even( ) )->evaluate( value = value ) ). ENDMETHOD. METHOD negate. result = COND #( WHEN truth = abap_true THEN abap_false ELSE abap_true ). ENDMETHOD. ENDCLASS.
Here, I define the odd predicate in Haskell by negating the even predicate. In ABAP, I encapsulate this logic in the zcl_predicate_odd class, which internally leverages the zcl_predicate_even class to evaluate evenness and then negate it. In this part, I use function composition in both languages. In functional programming, I believe function composition is the key to handling complexity.
Filtering Elements in a List in Haskell vs ABAP
Haskell
filter :: (a -> Bool) -> [a] -> [a] filter _ [] = [] filter pred (x:xs) | pred x = x : filter pred xs | otherwise = filter pred xs
ABAP
CLASS zcl_filter DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. METHODS get_filtered IMPORTING predicate TYPE REF TO zif_predicate value_tab TYPE ANY TABLE RETURNING VALUE(result) TYPE REF TO data. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_filter IMPLEMENTATION. METHOD get_filtered. FIELD-SYMBOLS <result_tab> LIKE value_tab. CREATE DATA result LIKE value_tab. ASSIGN result->* TO <result_tab>. LOOP AT value_tab ASSIGNING FIELD-SYMBOL(<value>). IF predicate->evaluate( <value> ) = abap_false. CONTINUE. ELSE. INSERT <value> INTO TABLE <result_tab>. ENDIF. ENDLOOP. ENDMETHOD. ENDCLASS.
In both languages, I've implemented the filter function as a higher-order function. In Haskell, it operates on lists, and in ABAP, it uses a generic table structure. The ABAP implementation defines a class zcl_filter that takes a predicate and a table of values, returning a filtered result.
In imperative programming languages, including ABAP, I always prefer to use loops over recursive methods. Handling generic data here becomes more complex but still acceptable. In this method, I observe the utilization of higher-order functions in ABAP through the implementation of dependency injection.
While in functional programming, functions are considered first-class citizens, in Object-Oriented Programming (OOP), objects take on this primary role.
Usage in GHCi vs ABAP Demo
ABAP
CLASS zcl_demo_fp DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_oo_adt_classrun. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_demo_fp IMPLEMENTATION. METHOD if_oo_adt_classrun~main. TYPES ty_t_integer TYPE STANDARD TABLE OF i WITH EMPTY KEY. DATA(filter) = NEW zcl_filter( ). DATA(even) = CAST zif_predicate( NEW zcl_predicate_even( ) ). DATA(odd) = CAST zif_predicate( NEW zcl_predicate_odd( ) ). DATA value_tab TYPE ty_t_integer. " get even number from 1 to 100 out->write( `Even Numbers` ). DATA(even_number) = filter->get_filtered( predicate = even value_tab = VALUE ty_t_integer( FOR i = 1 THEN i + 1 UNTIL i = 100 ( i ) ) ). ASSIGN even_number->* TO FIELD-SYMBOL(<even_number>). IF <even_number> IS ASSIGNED. value_tab = CORRESPONDING #( <even_number> ). DATA(string_even) = REDUCE string( INIT evens TYPE string FOR <even> IN value_tab NEXT evens = COND #( WHEN evens IS INITIAL THEN <even> ELSE |{ evens }, { <even> }| ) ). out->write( EXPORTING data = |[{ string_even }]| ). ENDIF. " get odd number from 1 to 100 out->write( `Odd Numbers` ). DATA(odd_number) = filter->get_filtered( predicate = odd value_tab = VALUE ty_t_integer( FOR i = 1 THEN i + 1 UNTIL i = 100 ( i ) ) ). ASSIGN odd_number->* TO FIELD-SYMBOL(<odd_number>). IF <odd_number> IS ASSIGNED. CLEAR value_tab. value_tab = CORRESPONDING #( <odd_number> ). DATA(string_odd) = REDUCE string( INIT odds TYPE string FOR <odd> IN value_tab NEXT odds = COND #( WHEN odds IS INITIAL THEN <odd> ELSE |{ odds }, { <odd> }| ) ). out->write( EXPORTING data = |[{ string_odd }]| ). ENDIF. ENDMETHOD. ENDCLASS.
In this chapter, we explored basic ideas in functional programming, focusing on two important things: higher-order functions and function composition. Here's what you need to remember:
Contributors
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
7 | |
6 | |
4 | |
3 | |
3 | |
2 | |
2 | |
2 | |
2 |