Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Translating a simple imperative algorithm to functional style

I recently made a small algorithm to strip out function arguments from a snippet of code and only keep the outermost functions.
I found that this algorithm was very easy to design in an imperative way.
However, I'm really interested in functional programming and I was wondering how you would accomplish the same thing in a functional way.

It would be very helpful to me if you could show me how such an algorithm might work, so I might get a better idea of how functional programming works. Also I'd like to know what your thought process is while designing the algorithm.

I made the imperative version in Python, but your answer doesn't have to be in python; haskell or any other language will do just as well.

Here's what it does (taking a string as input and returning a string):

"foo(a.d, b.e.fi()).go(sd, ds())"     -- returns -->  "foo().go()"
"foo(a, b).bar().fuu"                 -- returns -->  "foo().bar().fuu"
"foo.bar"                             -- returns -->  "foo.bar"

And here's my imperative code:

def get_rid_of_arguments(text):
    i, start, end = 0, 0, 0
    result = ""
    for j, c in enumerate(text):
        if c == '(':
            if i == 0:
                start = j
                result += text[end:start]
            i += 1
        elif c == ')':
            i -= 1
            if i == 0:
                end = j + 1
                result += '()'
    return result + text[end:]
like image 503
Zinggi Avatar asked Dec 11 '22 10:12

Zinggi


1 Answers

Here's my version:

import Control.Monad
import Control.Monad.State

-- filter `str` with the "stateful" monadic predicate function `handleChar`, 
-- with an initial state of 0
getRidOfArguments :: String -> String
getRidOfArguments str = filterM handleChar str `evalState` 0

handleChar :: Char -> State Int Bool
handleChar '(' = modify (+1) >> gets (<= 1)
handleChar ')' = modify (max 0 . subtract 1) >> gets (== 0)
handleChar _   = gets (== 0)

My thought process was: we're filtering a list so filter comes to mind; however whether we keep or drop a character depends on some state (our count of open/closed parens). So the monadic filter function filterM is appropriate, and we can use the State monad to abstract that plumbing of our open/close count.

Let me know if you want more details on how the above works.

like image 190
jberryman Avatar answered Mar 07 '23 15:03

jberryman