More efficient way in CL

I physically and mentally refuse to believe that this:
cellErrorMessage(1,2): when this.cellNumericValue(1,2) <0 "Enter a positive number." otherwise "" cellErrorMessage(2,2): when this.cellNumericValue(2,2) <0 "Enter a positive number." otherwise "" cellErrorMessage(3,2): when this.cellNumericValue(3,2) <0 "Enter a positive number." otherwise "" cellErrorMessage(4,2): when this.cellNumericValue(4,2) <0 "Enter a positive number." otherwise "" cellErrorMessage(5,2): when this.cellNumericValue(5,2) <0 "Enter a positive number." otherwise "" cellErrorMessage(6,2): when this.cellNumericValue(6,2) <0 "Enter a positive number." otherwise "" cellErrorMessage(7,2): when this.cellNumericValue(7,2) <0 "Enter a positive number." otherwise ""

Is the best way to make every cell in a table show a error message when the value is less than 0. What if I had 10 cells, or 20? That would be absolute torture. Are there loops in CL, like in python where:
for items in list:
print(items)?
If so, please, please, please tell me!

Also,
what is exactly is the point of parseEquation(mathbox.latex).differenceFunction("x")? What does it do? I’ve heard that it’s necessary when trying to check if input for a math response is something, like correct: check.

Also, does the argument .differenceFunction takes have to be x?

Welcome to CL! One of the first and hardest things to get used to is that CL does not operate like Python or other typical languages like that. It does not operate sequentially (except within a when … otherwise statement), it does not do native calculation operations (you need to define functions or use numeric value), and so on. So some things will be more complex than it feels like it needs to be - and some other things will be much simpler.

There is list support within CL, including list comprehensions, which will make things significantly easier. Here is a cleaned up example of what you have above - once you get the hang of it, the copy/paste part for the 20 cells is not that big a deal.

Here is a link in the Resources category that explains everything about how to use lists.

Feel free to ask for help on specific things that you are trying to make work.

1 Like

differenceFunction will return a function object in the form RHS - LHS = 0. You can define it with any variables you like. The most typical probably is to use it with “x” and “y” for a standard 2-variable function. You can then use the evaluateAt method of the function object to evaluate inputs, or you can sink the function object into a graph component. Are you familiar with the CL documentation? It has good examples for all of the typical things you would do. And the green triangles in the top right of each example take you to an activity that generally has multiple examples built out that you can copy and modify.

Wow! That’s very cool, but it’s sad to hear that I can’t avoid having to duplicate all those lines of code and then having to individually edit them to go to each cell.

I just learned that .map is kind of like the for loop in Python using the article to linked, and el is the element it’s looping through, like items!

And just to ask, what operator is =>?

Thanks! I’m used to coding languages like Java, Python, and R so it’s going to be a difficult adaptation to CL.

Yes, I am aware of the documentation, I just don’t use it a lot. But I will use it more now that you say it’s pretty good.

For the .differenceFunction, does it mean if the math input was x + 1 = 5, and I did parseEquation(math.latex).differenceEquation("x"), I would get x + 1 - 5 = 0, and then I have a line correct: math.evaluateAt(4) = 0? You mentioned I can sink the function, what sink is that?

Thank you a lot, and sorry if I’m asking too many questions haha :smile:

Currently I’m just playing around with CL, I’m not actually creating anything yet.

Look at the link I sent from the Resources category - it explains the arrow operator in detail.

It’s RHS - LHS, so “x + 1 = 5” would yield a function like f(x) = 5 - (x + 1) when you use differenceFunction(“x”). So yes, evaluateAt(4) should equal 0 to check for correctness.

Ok, I will check out the documentation on =>.

Thanks for clarifying the evalueAt source, but why doesn’t this work?
(I created this as a quick, mock-test example right after you gave me your response)

@Daniel_Wekselgreene

I think this issue is that you are using parseEquation, which is expecting an equation. In your example, it looks like you would only type in a single number, so you don’t get a valid equation object to work with. It will work if you type in x = 9, etc for all values.

You can access the element of a list using the [] operator. So in this example, since you are just comparing simple numeric values, you just want to use something like content[1] = 9

I showed how to fix this in the second screen, and then how I would actually do it on the third, since you can compare student answers against the table values, and you don’t need to hard code in the answers.

That’s really cool! I thought that parseEquation is just for all values (only numbers and equations) but seems like if you just want a value you can just use this.cellContent = solution and put that into a loop to check all of it.

Thanks a lot! I have one more question: If I were to do this with an equation would I use parseEquation? If yes, please give me an example.

I think this answer is only partly true. It is true that it’s not like Python in that it’s not an imperative language, but most functional languages (e.g. Haskell) and most logic programming languages (e.g. Prolog) could express these concepts succinctly without the duplicated code.

I’m not sure why CL couldn’t have something like

cellErrorMessage(i, 2): 
    when this.cellNumericValue(i, 2) < 0 "Enter a positive number." 
    otherwise ""

But one key difference from any other programming language is that usually there would be someone working on the language itself, whereas here I think that after Eric left, the language has fossilised. Unless I’m wrong, in which case, I’d love to hear a rationale from someone for why it cannot have a feature like the one outlined (even if it’s just implemented in some sort of macro pre-processor that compiles down to the original CL).

Also to save others from having to copy-and-edit the improved code, the suggested improvement is below, which doesn’t look like the most robust code (imagine you wanted to add another row, for instance.)

#create a list of the latex strings of each cell
contentList = [
  this.cellContent(1,1),
  this.cellContent(2,1),
  this.cellContent(3,1),
  this.cellContent(4,1),
  this.cellContent(5,1),
  this.cellContent(6,1),
  this.cellContent(7,1),
  this.cellContent(8,1),
  this.cellContent(9,1),
  this.cellContent(10,1)
]

#this creates a list of error messages for each element in contentList
errorMessages = contentList.map( (el) => when numericValue(el) < 0 "Enter a positive number." otherwise "")

#this part is unavoidable, sorry!
cellErrorMessage(1, 1): errorMessages[1]
cellErrorMessage(2, 1): errorMessages[2]
cellErrorMessage(3, 1): errorMessages[3]
cellErrorMessage(4, 1): errorMessages[4]
cellErrorMessage(5, 1): errorMessages[5]
cellErrorMessage(6, 1): errorMessages[6]
cellErrorMessage(7, 1): errorMessages[7]
cellErrorMessage(8, 1): errorMessages[8]
cellErrorMessage(9, 1): errorMessages[9]
cellErrorMessage(10, 1): errorMessages[10]

I didn’t mean to suggest that it was inherently unavoidable in the design of CL (which I personally don’t have any knowledge of), just that it is unavoidable the way CL currently is. I agree that it would be great not to have to sink values one by one!

1 Like

Yes, I totally agree that CL should have a simpler loop definition!

Very odd that the developers didn’t choose to implement a for or while loop.