# Exercise: Row Polymorphism
#
# Seq's type system has a powerful feature: TYPE VARIABLES.
#
# Look at `dup`:
#   42 dup        -> 42 42      (works with Int)
#   "hi" dup      -> "hi" "hi"  (works with String)
#   true dup      -> true true  (works with Bool)
#
# How? The full type has two kinds of variable:
#   : dup ( ..a A -- ..a A A )
#
# `..a` is a ROW VARIABLE that stands for "the rest of the
# stack, whatever it is, passing through untouched." `A` is a
# TYPE VARIABLE that stands for "the type of the top element,
# whatever it is."
#
# The type variable alone (matching any single type) is
# parametric polymorphism. The row variable (matching any
# stack tail) is what makes this ROW POLYMORPHISM — words
# work on ANY stack, as long as the top elements match.
#
# Your task: Implement `keep` — a combinator that runs a quotation
# on the top value but leaves the original underneath the result.
#
# Example:
#   5 [ dup i.* ] keep   -> ( 25 5 )    # squared, original kept
#
# Signature: ( ..a A [ ..a A -- ..b ] -- ..b A )
#   - `..a` is the row beneath us — whatever else is on the stack.
#   - On top of that: the value A and a quotation.
#   - The quotation consumes A (and may touch ..a) leaving ..b on top.
#   - keep returns whatever the quotation left (..b), with the
#     original A restored on top.
#
# Hint: you will need to make a copy of the value before calling
# the quotation, so a copy survives for the result stack.
#
# When done, delete the marker line below.

# I AM NOT DONE

: keep ( ..a A [ ..a A -- ..b ] -- ..b A )
    # Your code here
    # 1. Save the original value somehow
    # 2. Run the quotation
    # 3. Put the original back
    drop drop 0  # placeholder
;

: test-row-polymorphism ( -- )
    # Test with Int
    5 [ dup i.* ] keep   # 5 squared = 25, keep 5
    5 test.assert-eq     # original value
    25 test.assert-eq    # computed value

    # Same function works with String!
    "hello" [ string.length ] keep
    "hello" string.equal? test.assert  # original
    5 test.assert-eq                   # length

    # This is the power of row polymorphism:
    # ONE definition works with ANY type
;
