Beispiel #1
0
    def getArity(self, fn):
        """
        Function:

        - Gets the arity (number of inputs left to be specified) of a function or method (curried or uncurried)

        Requires:

        - `fn`:
            - Type: function | method
            - What: The function or method to get the arity of
            - Note: Class methods remove one arity to account for self

        Examples:

        ```
        p.getArity(p.zip) #=> 2
        curriedZip=p.curry(p.zip)
        ABCuriedZip=curriedZip(['a','b'])
        p.getArity(ABCuriedZip) #=> 1
        ```
        """
        if isinstance(fn, curry_fn):
            return fn.__arity__
        return curry_fn(fn).__arity__
Beispiel #2
0
    def thunkify(self, fn):
        """
        Function:

        - Creates a curried thunk out of a function
        - Evaluation of the thunk lazy and is delayed until called

        Requires:

        - `fn`:
            - Type: function | method
            - What: The function or method to thunkify
            - Note: Thunkified functions are automatically curried
            - Note: Class methods auto apply self during thunkify

        Notes:

        - Input functions are not thunkified in place
        - The returned function is a thunkified version of the input function
        - A curried function can be thunkified in place by calling fn.thunkify()

        Examples:

        ```
        def add(a,b):
            return a+b

        addThunk=p.thunkify(add)

        add(1,2) #=> 3
        addThunk(1,2)
        addThunk(1,2)() #=> 3

        x=addThunk(1,2)
        x() #=> 3
        ```

        ```
        @p.curry
        def add(a,b):
            return a+b

        add(1,2) #=> 3

        add.thunkify()

        add(1,2)
        add(1,2)() #=> 3
        ```
        """
        if not isinstance(fn, curry_fn):
            fn = curry_fn(fn)
        else:
            fn = fn()
        return fn.thunkify()
Beispiel #3
0
    def map(self, fn, data):
        """
        Function:

        - Maps a function over a list or a dictionary

        Requires:

        - `fn`:
            - Type: function | method
            - What: The function or method to map over the list or dictionary
            - Note: This function should have an arity of 1
        - `data`:
            - Type: list | dict
            - What: The list or dict of items to map the function over

        Examples:

        ```
        data=[1,2,3]
        p.map(
            fn=p.inc,
            data=data
        )
        #=> [2,3,4]
        ```

        ```
        data={'a':1,'b':2,'c':3}
        p.map(
            fn=p.inc,
            data=data
        )
        #=> {'a':2,'b':3,'c':4}
        ```

        """
        if not isinstance(fn, curry_fn):
            fn = curry_fn(fn)
        if fn.__arity__ != 1:
            self.exception('`map` `fn` must be unary (take one input)')
        if not isinstance(data, (list, dict)):
            self.exception('`map` `data` must be a list or a dict')
        if not len(data) > 0:
            self.exception(
                '`map` `data` has a length of 0 or is an empty dictionary, however it must have at least one element in it'
            )
        if isinstance(data, dict):
            return {key: fn(value) for key, value in data.items()}
        else:
            return [fn(i) for i in data]
Beispiel #4
0
    def accumulate(self, fn, initial_accumulator, data):
        """
        Function:

        - Returns an accumulated list of items by iterating a function starting with an accumulator over a list

        Requires:

        - `fn`:
            - Type: function | method
            - What: The function or method to reduce
            - Note: This function should have an arity of 2 (take two inputs)
            - Note: The first input should take the accumulator value
            - Note: The second input should take the data value
        -`initial_accumulator`:
            - Type: any
            - What: The initial item to pass into the function when starting the accumulation process
        - `data`:
            - Type: list
            - What: The list of items to iterate over

        Example:

        ```
        data=[1,2,3,4]
        p.accumulate(
            fn=p.add,
            initial_accumulator=0,
            data=data
        )
        #=> [1,3,6,10]

        ```
        """
        if not isinstance(fn, curry_fn):
            fn = curry_fn(fn)
        if fn.__arity__ != 2:
            self.exception(
                '`reduce` `fn` must have an arity of 2 (take two inputs)')
        if not isinstance(data, (list)):
            self.exception('`reduce` `data` must be a list')
        if not len(data) > 0:
            self.exception(
                '`reduce` `data` has a length of 0, however it must have a length of at least 1'
            )
        acc = initial_accumulator
        out = []
        for i in data:
            acc = fn(acc, i)
            out.append(acc)
        return out
Beispiel #5
0
    def curry(self, fn):
        """
        Function:

        - Curries a function such that inputs can be added interatively

        Requires:

        - `fn`:
            - Type: function | method
            - What: The function or method to curry
            - Note: Class methods auto apply self during curry

        Notes:

        - Once curried, the function | method becomes a curry_fn object
        - The initial function is only called once all inputs are passed


        Examples:

        ```
        curriedZip=p.curry(p.zip)
        curriedZip(['a','b'])([1,2]) #=> [['a',1],['b',2]]

        # Curried functions can be thunkified at any time
        # See also thunkify
        zipThunk=curriedZip.thunkify()(['a','b'])([1,2])
        zipThunk() #=> [['a',1],['b',2]]
        ```

        ```
        def myFunction(a,b,c):
            return [a,b,c]

        curriedMyFn=p.curry(myFunction)

        curriedMyFn(1,2,3) #=> [1,2,3]
        curriedMyFn(1)(2,3) #=> [1,2,3]

        x=curriedMyFn(1)(2)
        x(3) #=> [1,2,3]
        x(4) #=> [1,2,4]


        ```
        """
        if not isinstance(fn, curry_fn):
            return curry_fn(fn)
        return fn
Beispiel #6
0
    def adjust(self, index, fn, data):
        """
        Function:

        - Adjusts an item in a list by applying a function to it

        Requires:

        - `index`:
            - Type: int
            - What: The 0 based index of the item in the list to adjust
            - Note: Indicies are accepted
            - Note: If the index is out of range, picks the (-)first / (+)last item
        - `fn`:
            - Type: function | method
            - What: The function to apply the index item to
            - Note: This is automatically curried
        - `data`:
            - Type: list
            - What: The list to adjust

        Example:

        ```
        data=[1,5,9]
        p.adjust(
            index=1,
            fn=p.inc,
            data=data
        ) #=> [1,6,9]
        ```
        """
        if not isinstance(index, int):
            self.exception('`index` must be an int')
        if not isinstance(data, list):
            self.exception('`data` must be a list')
        if not isinstance(fn, curry_fn):
            fn = curry_fn(fn)
        index = self.clamp(-len(data), len(data) - 1, index)
        data[index] = fn(data[index])
        return data
Beispiel #7
0
    def flip(self, fn):
        """
        Function:

        - Returns a new function equivalent to the supplied function except that the first two inputs are flipped

        Requires:

        - `fn`:
            - Type: function | method
            - What: The function or method to flip
            - Note: This function must have an arity of at least 2 (take two inputs)
            - Note: Only args are flipped, kwargs are passed as normal

        Notes:

        - Input functions are not flipped in place
        - The returned function is a flipped version of the input function
        - A curried function can be flipped in place by calling fn.flip()
        - A function can be flipped multiple times:
            - At each flip, the first and second inputs for the function as it is currently curried are switched
            - Flipping a function two times before adding an input will return the initial value

        Examples:

        ```
        def concat(a,b,c,d):
            return str(a)+str(b)+str(c)+str(d)

        flip_concat=p.flip(concat)

        concat('fe-','fi-','fo-','fum') #=> 'fe-fi-fo-fum'
        flip_concat('fe-','fi-','fo-','fum') #=> 'fi-fe-fo-fum'
        ```

        ```
        @p.curry
        def concat(a,b,c,d):
            return str(a)+str(b)+str(c)+str(d)

        concat('fe-','fi-','fo-','fum') #=> 'fe-fi-fo-fum'

        concat.flip()

        concat('fe-','fi-','fo-','fum') #=> 'fi-fe-fo-fum'
        ```

        ```
        @p.curry
        def concat(a,b,c,d):
            return str(a)+str(b)+str(c)+str(d)

        a=p.flip(concat)('fi-')
        b=p.flip(a)('fo-')
        c=p.flip(b)('fum')
        c('fe-') #=> 'fe-fi-fo-fum'
        ```

        ```
        def concat(a,b,c,d):
            return str(a)+str(b)+str(c)+str(d)

        a=p.flip(concat)('fi-').flip()('fo-').flip()('fum')
        a('fe-') #=> 'fe-fi-fo-fum'
        ```
        """
        if not isinstance(fn, curry_fn):
            fn = curry_fn(fn)
        else:
            fn = fn()
        return fn.flip()