220 project but its one line

name: 220proj2.md
category: school
date: 1/9/2024

So 220 is Programming Methodology which is basically just typescript. I am very good at typescript/javascript. We had 8 projects, the third of which was about what's basically a recursively defined linked list (list(1, list(2, list(3))) would be 1->2->3). I was doing the project like normal and most of the functions ended up being just chains of higher order functions or close to it--usually just a reduce or something.

I saw this and saw an opportunity. If I could squash the last two functions into one line then I could submit the entire assignment in a single expression. This is due to two properties of javascript: First that you can assign and export multiple variables in a single expression, and second that, using anonymous functions, you can reference functions not yet defined at that point in the code given that they will be within scope at time of execution.

For an example, the following code will work as expected

export const [a, b] = [1, () => a+1] // a => 1, b() => 2

notably, however, the following will not work

export const [a, b] = [1, a+1] // ReferenceError: Cannot acess 'a' before initialization

anyways as long as I could do every single question using a chain of higher order functions (e.g. in one expression), I could do the entire assignemnt in a single line. So let's look at the ones that stopped me for a bit:

everyNRev and this random helper method called products

The un-one-line-ified code looks like this:

export function everyNRev<T>(lst: List<T>, n: number): List<T> {
  let i=1
  return lst.reduce((acc, elem) => i++ % n === 0 ? node(elem, acc) : acc, empty())
}

and the other function

export function products(lst: List<number>, comparator: (a: number) => boolean): List<number> {
  let prod = 1;
  return reverseList(lst.reduce((acc, elem) => {
    if (comparator(elem)) { prod = 1; return acc }
    return node((prod *= elem), acc);
  }, empty()));
}
//used in negativeProducts and nonNegativeProducts
export const negativeProducts=(lst:List<number>)=>products(lst, a=>a<0)
export const nonNegativeProducts=(lst:List<number>)=>products(lst, a=>a>=0)

The issue for both of these is the same. I have to keep track of some variable outside the reduction. While I can modify it in an expression, I can't easily set it within an expression (yes I could techincally but it woulda been weird and I didn't want to). But even if I could, it doesn't change the fact that I still have to declare it in the first place, and I couldn't simply put it in the function as a default parameter because 1. I would probably be docked points in the manual grading and 2. while the autograder probably wouldn't catch it, I can't be completely sure.

How did I fix the issue? It actually came from a flash of insight by one of my roommates Isaac. He was talking about how he did a problem and he was talking about "reducing over two variables" and I was like "you can do that?" and apparently I just misunderstood him but then I realized that yes, you can do that. You can simply reduce over a list with two elements, one of them being basically an extra variable that you can declare, and the other being the thing you actually want to output after the reduction. With this realization, I turned that code into the following beauties:

const everyNRev=<T>(lst:List<T>,n:number)=>lst.reduce(([i, acc], elem) => (i=i as number) % n === 0 ? [i+1, node(elem, acc as List<T>)] : [i+1, acc], [1, empty()])[1] as List<T>
const products=(lst:List<number>,comparator:(a:number)=>boolean)=>reverseList(lst.reduce(([prod, acc], elem) => comparator(elem) ? [1, acc] : [prod=prod as number * elem, node(prod, acc as List<number>)], [1, empty()])[1] as List<number>)

All the casting is because I didn't really know how to do like [number, List] types then so I kinda just had to promise tsc that everything was what it was supposed to be.

now I probably can't show the entire assignment because like idk what if someone finds this and plagiarizes it or something, but I'll show you what the final output kinda looked like with just four functions. I'm also going to make it actually one line because I legit am kinda scared that people will try to plagiarize (even though it would be incredibly obvious, don't do that) so that it's kinda unreadable. Everything else is exactly as it is from the submission lol

import { List, node, empty, reverseList } from "../include/lists.js";
//this is all in one line bceause I can
//please do not dock me points
//readability technically isn't in the specs
export const [everyNRev, products, nonNegativeProducts, negativeProducts]=[<T>(lst:List<T>,n:number)=>lst.reduce(([i, acc], elem) => (i=i as number) % n === 0 ? [i+1, node(elem, acc as List<T>)] : [i+1, acc], [1, empty()])[1] as List<T>, (lst:List<number>,comparator:(a:number)=>boolean)=>reverseList(lst.reduce(([prod, acc], elem) => comparator(elem) ? [1, acc] : [prod=prod as number * elem, node(prod, acc as List<number>)], [1, empty()])[1] as List<number>), (lst:List<number>)=>products(lst, a=>a<0), (lst:List<number>)=>products(lst, a=>a>=0)]

afterwards

I got a 90 beacause of an autograder error. I asked the professor in an email to fix it because my code was good and he was like "yeah k I'll do that also cool that it's in one line but also this is terrible code" and I was like "yeah this is terrible code but I saw the chance and I had to take it." He basically shouted me out in the following class, being like "So our solution was about 50 lines long, but some people did much longer and some people did much shorter. I even saw a solution that was only a single line." Isaac and I were actually so hyped about getting shouted out and honestly it might have been the highlight of my semester. When I was turning in my first exam he saw my name and was like "oh you're that guy" and makes like a gesture with his hands, I guess to indicate something small and I was like "yeah!! :) also you haven't given me back my points"

I never did get those points back though (it did not matter it wouldn't have changed my grade)

He also said that even though readability was technically not in the specs he would consider adding it in the future so if you're a future 220 student reading this who wants to do something like this but would get docked points for it, uh, sorry--