Curry and partial application in Ruby - Time & Space Complexity
When using curry and partial application, we want to know how the time to run the code changes as we give it more inputs.
We ask: How does the number of steps grow when we call the curried or partially applied function multiple times?
Analyze the time complexity of the following Ruby code using curry and partial application.
add = ->(a, b, c) { a + b + c }
curried_add = add.curry
partial_add = curried_add.call(1)
result = partial_add.call(2).call(3)
This code creates a curried version of a function that adds three numbers, then partially applies the first argument, and finally calls the remaining arguments one by one.
Look for repeated steps or calls in the code.
- Primary operation: Calling the curried function multiple times to supply arguments.
- How many times: Once per argument after currying (here, two calls after the first partial call).
Each argument requires one function call after currying.
| Input Size (n) | Approx. Operations |
|---|---|
| 3 (arguments) | 3 calls (one initial, two after) |
| 10 (arguments) | 10 calls (one initial, nine after) |
| 100 (arguments) | 100 calls (one initial, ninety-nine after) |
Pattern observation: The number of calls grows linearly with the number of arguments supplied.
Time Complexity: O(n)
This means the time to fully call a curried function grows in a straight line with the number of arguments.
[X] Wrong: "Currying makes the function run faster because it breaks calls into smaller parts."
[OK] Correct: Currying changes how you call the function but does not reduce the total work; each argument still needs to be processed, so total time grows with the number of arguments.
Understanding how currying affects time helps you explain function calls clearly and shows you can think about how code scales, a useful skill in many programming tasks.
What if we changed the curried function to accept all arguments at once instead of one by one? How would the time complexity change?
Practice
Solution
Step 1: Understand currying concept
Currying transforms a function so you can call it with fewer arguments than it needs.Step 2: Result of currying
When called with fewer arguments, it returns a new function waiting for the rest.Final Answer:
Call the function with fewer arguments and get a new function -> Option AQuick Check:
Currying = call fewer args, get new function [OK]
- Thinking currying speeds up code
- Confusing currying with memoization
- Believing currying changes function to class method
Solution
Step 1: Recall Ruby syntax for currying
In Ruby, you call the .curry method on a lambda or Proc object.Step 2: Identify correct usage
Callingmy_lambda.curryreturns a curried version of the lambda.Final Answer:
my_lambda.curry -> Option DQuick Check:
Use .curry method on lambda object [OK]
- Trying to call curry as a standalone function
- Using .partial instead of .curry
- Passing lambda as argument to curry method
add = ->(x, y) { x + y }
curried_add = add.curry
add_five = curried_add.call(5)
puts add_five.call(3)Solution
Step 1: Understand currying and calls
The lambda add takes two arguments and returns their sum. Currying allows calling with one argument to get a new function.Step 2: Trace the calls
curried_add.call(5) returns a new function that adds 5 to its argument. Calling add_five.call(3) returns 5 + 3 = 8.Final Answer:
8 -> Option CQuick Check:
Curried add with 5 then 3 = 8 [OK]
- Expecting add_five to be a number, not a function
- Confusing call with direct invocation
- Thinking currying changes output type
multiply = ->(x, y) { x * y }
curried_multiply = multiply.curry
result = curried_multiply(2)(3)
puts resultSolution
Step 1: Check syntax for currying and calling
In Ruby, lambdas can be curried and called using parentheses like functions.Step 2: Verify code behavior
curried_multiply(2) returns a function that multiplies by 2; calling (3) returns 6. The code runs without error.Final Answer:
No error, code runs correctly and prints 6 -> Option BQuick Check:
Currying with lambdas and calls works as shown [OK]
- Thinking .call is required for every call
- Believing curry is not available for lambdas
- Assuming lambdas must be defined with def
concat = ->(a, b, c) { "#{a}-#{b}-#{c}" }
curried_concat = concat.curry
partial = curried_concat.call('X').call('Y')
puts partial.call('Z')
What does this demonstrate about currying and partial application?Solution
Step 1: Analyze the currying calls
The original lambda takes 3 arguments and joins them with dashes. Currying allows calling with one argument at a time.Step 2: Understand partial application here
Calling curried_concat.call('X') fixes the first argument. Then .call('Y') fixes the second. The resulting function waits for the third argument.Step 3: Output and meaning
Calling partial.call('Z') returns "X-Y-Z". This shows partial application by fixing some arguments step-by-step.Final Answer:
You can fix some arguments step-by-step, creating simpler functions -> Option AQuick Check:
Currying enables partial application stepwise [OK]
- Thinking all args must be given at once
- Confusing currying with separate partial method
- Assuming partial calls cause errors
Ready to prove it?
Pass the test and this pattern moves unknown
