KS5 · AQA A-level Computer Science (VB.NET) · Papers 2

K5CS12 · Functional programming, functions and lists

Interactive
revision
Gap
finder
PLCDicey
words
BingoEscape
room
HTML
Playground
Python
Lab
Exam
builder
AI Exam
Practice
QuizTeachYouTube

Revise the key ideas

Function types, application and values

  • Functions as mappings — A mathematical function assigns exactly one result to each input in its stated domain. The type f: A → B identifies an argument type/set A and result type/set B. The codomain contains all permitted result values, while the actual image/range is the subset obtained; a function need not produce every member of its codomain.
  • Domain and finite example — For f: {1,2,3} → {1,2,3,4,5,6} with f(x) = 2x, the image is {2,4,6}. Input 4 is outside this declared domain even though the arithmetic expression can be evaluated more widely in another definition. A type or domain restriction is part of the function's meaning, not just an optional comment on its formula.
  • Exactly one output — A rule assigning two different results to the same input is not a single-valued function under this model. Distinct inputs can share one result: squaring both 2 and −2 gives 4. Do not confuse single-valued with one-to-one, or assume every function has an inverse function over its whole codomain.
  • Function application — Application supplies an argument to a function and evaluates the associated result. If double(x) = 2x, then double(5) = 10. Referring to double as a value is different from applying double(5) now; a higher-order operation can receive the former to apply later to several inputs.
  • Product argument types — An uncurried addition function can have type add: Integer × Integer → Integer, taking one ordered-pair argument such as (3,4) and returning 7. Programming syntax often describes this as two arguments. The order of components matters for a noncommutative operation such as subtraction, even when it does not affect addition's result.
  • First-class function values — First-class values can occur in expressions, be bound to variables, passed as arguments and returned from calls. Functions can be such values in functional languages and multiparadigm languages with relevant support. First-class does not mean that every function is pure or that the program must never interact with external devices.
  • VB.NET function values — In the original VB.NET examples, Func(Of Integer, Integer) describes a delegate, a typed reference to callable code, accepting an Integer and returning an Integer. A lambda Function(x As Integer) x * x creates an anonymous function value, a function written without a separate routine name. The language supports functional techniques alongside imperative features; using a Function keyword alone does not make code pure.

    Original compiled VB.NET excerpt.

    Option Strict On
    Imports System
    Imports System.Collections.Generic
    
    Module Example
        Function Add(a As Integer) As Func(Of Integer, Integer)
            Return Function(b As Integer) a + b
        End Function
    
        Function Combine(a As Integer) As Func(Of Integer, Func(Of Integer, Integer))
            Return Function(b As Integer) Function(c As Integer) a + 10 * b + 100 * c
        End Function
    End Module
  • Purity and explicit dependencies — A pure transformation depends on explicit inputs and avoids relevant observable side effects. A function reading a mutable global or current clock has an additional dependency not represented by the same explicit argument alone. Keep console/file interaction at an appropriate boundary so pure calculation can be reasoned about and tested separately.

Partial application and composition

  • Curried type — The curried addition type Integer → (Integer → Integer) says that applying one integer returns a function expecting the next. Arrows conventionally associate to the right, so Integer → Integer → Integer means the same grouping. This differs from the product-input type Integer × Integer → Integer, although a suitable wrapper can connect the two representations.
  • Two-stage application — If add(a)(b) = a + b, add(4) returns a function that adds 4 to its later input. Applying that returned function to 7 gives 11. The partial result is a function, not the integer 4, an error or an automatic final sum; distinguish each stage's input and result type.
  • One-argument and full application — For f: A → B, supplying an A gives a B. If B is itself a function type, the result can accept a further argument; otherwise there is no unsupplied argument left. Partially applying a multi-stage function means fixing fewer of its arguments than needed for its final nonfunction result, not merely writing half of an arithmetic expression.
  • Three-stage example — Let combine(a)(b)(c) = a + 10b + 100c with integer inputs in the supported example range. combine(2) returns a two-stage function; combine(2)(3) returns the one-stage function c ↦ 32 + 100c; combine(2)(3)(4) returns 432. The positions are deliberately distinct so a trace cannot swap arguments without changing the result.
    For the declared combine(a)(b)(c)=a+10b+100c, applying 2 then 3 leaves the function c↦32+100c. Only applying 4 produces the final integer 432. Each arrow is an application stage; distinct argument weights make swapped positions visible.
    For the declared combine(a)(b)(c)=a+10b+100c, applying 2 then 3 leaves the function c↦32+100c. Only applying 4 produces the final integer 432. Each arrow is an application stage; distinct argument weights make swapped positions visible.
  • Closures and captured values — A returned function can retain relevant values from the environment in which it was created, such as the fixed 4 in add(4). This is a closure. Capturing a mutable variable that later changes can introduce a hidden changing dependency, so the examples fix explicit values rather than claiming every closure is automatically immutable or pure.
  • Composition order — For f: A → B and g: B → C, g ∘ f applies f first and g to its result, giving A → C. With f(x) = x + 2 and g(x) = x³, (g ∘ f)(2) = 64, while (f ∘ g)(2) = 10. The right-hand function acts first; the composition symbol is not ordinary multiplication.
    The noncommuting example f(x)=x+2 and g(x)=x cubed distinguishes composition order: g after f at 2 yields 64, while f after g yields 10. The right-hand function in the composition notation is applied first. Arrows describe value flow, not multiplication.
    The noncommuting example f(x)=x+2 and g(x)=x cubed distinguishes composition order: g after f at 2 yields 64, while f after g yields 10. The right-hand function in the composition notation is applied first. Arrows describe value flow, not multiplication.
  • Type compatibility — Composition requires the first function's relevant results to be acceptable inputs for the next. If parse returns a structured result including possible failure, it cannot simply be connected to an integer-only transformation without handling that possibility. A matching-looking variable name does not establish compatible types or valid domain membership.
  • Reusable composition — A Compose helper can accept two function values and return a new lambda applying them in the stated order. The returned function need not evaluate every possible input when created; evaluation happens when it is subsequently applied. Test noncommuting functions to detect a reversed composition implementation that an all-addition example might conceal.

    Original compiled VB.NET excerpt.

    Option Strict On
    Imports System
    Imports System.Collections.Generic
    
    Module Example
        Function Compose(g As Func(Of Integer, Integer), f As Func(Of Integer, Integer)) As Func(Of Integer, Integer)
            Return Function(x As Integer) g(f(x))
        End Function
    End Module

Higher-order map, filter and fold

  • Higher-order definition — A higher-order function accepts a function or returns a function, or both. Map, filter and fold accept transformation, predicate or combining functions respectively. Merely returning a list or using recursion does not meet this definition unless function values are actually passed or returned.
  • Map preserves correspondence — Map applies its supplied function to each element and returns the corresponding sequence of results in the defined order. Mapping square over [1,2,3,4] gives [1,4,9,16]. It preserves the number of elements for this total transformation; it does not automatically remove duplicates, reject odd values or combine all values into one.
  • Filter selects by predicate — Filter retains exactly the original elements satisfying its predicate in the relevant sequence order. Filtering even values from [1,2,3,4] gives [2,4]. A predicate returns a truth value; transforming every element into True or False is mapping the predicate, not filtering the original values.
  • Fold and accumulator — A fold combines a sequence using an explicit combining function and starting accumulator under a stated direction. A left fold of addition with initial 0 over [1,2,3,4] gives 10. The accumulator is a result passed between stages; a pure fold implementation can use recursion or an internal loop without exposing mutation of the input to callers.
  • Direction matters — Define foldLeft(op,z,[a,b,c]) as op(op(op(z,a),b),c). With subtraction, initial 10 and list [3,2], the result is 5. A right fold usually groups op(a,op(b,z)) for [a,b], which gives 3 − (2 − 10) = 11 here; definitions and argument order must be explicit, not inferred from a generic word reduce.
  • Empty input rules — Mapping or filtering an empty list returns an empty list. A fold with an explicit initial accumulator returns that initial value for an empty list. A reduce operation lacking an initial value may be undefined or raise an error on empty input, depending on the language/API; do not invent a universal zero result for all reductions.
  • Order and noncommutativity — String concatenation can be associative but not commutative, meaning order can change the result: joining a then b differs from b then a. A list fold normally follows its specified order; a parallel reduction needs suitable combining properties and order rules. Exact-integer sum examples do not justify regrouping subtraction or ignoring floating-point rounding.
  • Pipelines and transformation order — Filter even inputs from [1,2,3,4], then map square, gives [4,16]. Mapping plus 1 first then filtering evens gives [2,4], while filtering evens first then mapping plus 1 gives [3,5]. Reordering higher-order operations can change the answer; justify any claimed equivalence for the actual functions and domains.
  • VB.NET functional support — The supplied program implements MapValues, FilterValues and FoldLeft using Func delegates and returns fresh result arrays where appropriate. Internal loops keep the small teaching implementation direct; each operation's public behaviour preserves its supplied array. These arrays remain mutable VB.NET objects in general, so this usage is non-mutating rather than a false claim that every array type is immutable.

    Original compiled VB.NET excerpt.

    Option Strict On
    Imports System
    Imports System.Collections.Generic
    
    Module Example
        Function MapValues(values As Integer(), transform As Func(Of Integer, Integer)) As Integer()
            Dim result As New List(Of Integer)()
            For Each value As Integer In values
                result.Add(transform(value))
            Next
            Return result.ToArray()
        End Function
    
        Function FilterValues(values As Integer(), predicate As Func(Of Integer, Boolean)) As Integer()
            Dim result As New List(Of Integer)()
            For Each value As Integer In values
                If predicate(value) Then result.Add(value)
            Next
            Return result.ToArray()
        End Function
    
        Function FoldLeft(values As Integer(), initial As Integer, combineValues As Func(Of Integer, Integer, Integer)) As Integer
            Dim accumulator As Integer = initial
            For Each value As Integer In values
                accumulator = combineValues(accumulator, value)
            Next
            Return accumulator
        End Function
    End Module
  • Testing functional programs — Check empty and singleton inputs, mixed signs, order-sensitive operations, predicate boundaries and unchanged source values. Test partially applied functions independently with several later arguments. A successful displayed example is evidence for that case; broader correctness needs the relevant preconditions, reasoning and additional checks, not only a screenshot of output.

Head, tail and constructing lists

  • List meaning — A list is an ordered sequence whose elements may repeat, unlike a mathematical set. In a conventional functional list model, values are built from an empty list or a head element linked to a tail list. A VB.NET array can demonstrate the operations but has different representation and copying costs from a persistent linked list.
  • Head and tail — For [4,3,5], head is 4 and tail is [3,5]. The head is an element; the tail is a list, even when it has just one element or is empty. For singleton [4], the tail is [], not 4 and not an invented null element.
    For the conceptual list [4,3,5], head is the element 4 and tail is the list [3,5]. The singleton [4] has empty tail []. Combining head with tail reconstructs the original value sequence. This schematic does not present the colon as VB.NET source syntax or imply an array has the same sharing/copying costs as a persistent linked list.
    For the conceptual list [4,3,5], head is the element 4 and tail is the list [3,5]. The singleton [4] has empty tail []. Combining head with tail reconstructs the original value sequence. This schematic does not present the colon as VB.NET source syntax or imply an array has the same sharing/copying costs as a persistent linked list.
  • Empty-list boundary — [] represents an empty list and has length 0. Under the declared teaching API, requesting its head or tail raises an argument error; other languages/APIs can use option values or different defined behaviour. Check emptiness before taking a head in a recursive function whose base case is an empty list.

    Original compiled VB.NET excerpt.

    Option Strict On
    Imports System
    Imports System.Collections.Generic
    
    Module Example
        Function Head(values As Integer()) As Integer
            If values.Length = 0 Then Throw New ArgumentException("Head needs a nonempty sequence.")
            Return values(0)
        End Function
    
        Function Tail(values As Integer()) As Integer()
            If values.Length = 0 Then Throw New ArgumentException("Tail needs a nonempty sequence.")
            Dim result As New List(Of Integer)()
            For i As Integer = 1 To values.Length - 1
                result.Add(values(i))
            Next
            Return result.ToArray()
        End Function
    End Module
  • Constructing and counting — Construct an empty list explicitly, test whether it is empty and obtain its length using the representation's supported operations. Length counts elements rather than summing numeric values. A linked list may require traversal to calculate length unless cached, while an array stores bounds; do not promise one complexity for every representation.
  • Prepending an element — Prepending 2 to [4,3,5] produces [2,4,3,5]. In a singly linked immutable model, a new head cell can reference the old list as its tail, supporting structural sharing. The supplied array-based demonstration copies into a fresh array, so its cost differs even though the visible list result agrees.
  • Appending an element — Appending 2 to [4,3,5] produces [4,3,5,2]. In a simple immutable singly linked list, appending usually rebuilds the path through the existing cells, unlike constant-time prepend. The example's fresh array also copies; do not confuse appending one element with concatenating an entire second list or changing the first element.
  • Recursive decomposition — A list sum can use sum([]) = 0 and sum(head:tail) = head + sum(tail). For [4,3,5], the calls combine 4 + 3 + 5 + 0 = 12. The tail becomes shorter at each step, giving progress towards the base case for a finite list; a missing base case or unchanged recursive argument breaks that reasoning.

    Original compiled VB.NET excerpt.

    Option Strict On
    Imports System
    Imports System.Collections.Generic
    
    Module Example
        Function Prepend(value As Integer, values As Integer()) As Integer()
            Dim result As New List(Of Integer)()
            result.Add(value)
            result.AddRange(values)
            Return result.ToArray()
        End Function
    
        Function Append(values As Integer(), value As Integer) As Integer()
            Dim result As New List(Of Integer)(values)
            result.Add(value)
            Return result.ToArray()
        End Function
    
        Function RecursiveSum(values As Integer()) As Integer
            If values.Length = 0 Then Return 0
            Return Head(values) + RecursiveSum(Tail(values))
        End Function
    End Module
    ' RecursiveSum uses the Head/Tail helpers shown earlier.
  • Reconstructing a list — Prepending a nonempty list's head to its tail reconstructs the original sequence of values: 4:[3,5] = [4,3,5] in the declared conceptual notation. Reversing those roles or treating the tail as one nested element produces a different structure. The colon notation describes the functional-list model here and is not presented as VB.NET source syntax.
  • Application and practical evidence — Learners on the VB.NET route still need experience of these functional operations and function types. Compile and run the supplied original examples, alter predicates/transformations, predict results and explain source preservation and boundary behaviour. A vocabulary quiz can partially check concepts but cannot demonstrate independent construction, debugging or correct program execution.

Test yourself

50 questions · Random sets of 10. These quick checks support revision; practise longer explanations and justified judgements too.

Share this page

Social links open a draft in a new tab for you to review and send.

Report an error or bug

Please do not include your name, school, passwords or other personal information. Responses go to the website owner through Microsoft Forms. Open form in a new tab if it does not load here.