This is kind of nerdy, but I was thinking about starting with one operator, like division, and using it to create multiplication. However, I realized, that while you can write a multiplication problem with just division (3*4=3/(1/4)), but you cannot divide numbers using only multiplication. Is using only multiplication to create division impossible, or am I missing something? I just found it odd that it is easy to make multiplication from division, but not the other way around.
Maybe a mathematician will answer better ... but for me the idea is the same as when you learn numbers: naturals, integers, rationals ...
Until the division appears you do not need to enter the rationals. Only with direct multiplication do they not appear (they are not required). The division calls an "indirect" multiplication and therefore is something more "complete". A division of a division is really a division using rationals (not only integers).
It's the same as with the subtraction operation, the natural numbers and the integers.
I'm imagining you thinking "you can make addition out of subtraction; you just add the negative of the second number." That's because we happen to have a notation for "the negative of a number," namely -3 for the negative of 3. (If you're in elementary school you might see a raised negative sign ‾3 used to make the meaning unambiguous.)
There's a Unicode character ⅟that we could use to represent the reciprocal function, It includes a slash, which is unfortunate, but the negation symbol is exactly the same as the subtraction symbol. So we could say xy= x / (⅟y). (The more usual notation is y‾¹.)
If you're interested in inventing arithmetic operators starting with a minimal set, try doing it with nothing but gray rings and CALL blocks. Addition and multiplication are pretty easy, then it gets a lot harder, The number representation (nonnegative integers only) is, e.g.,
3= (λx (λf (f (f (f x,)))) where λ is a gray ring with x or f as its input name. The way you make the integers is you start with zero, (λx (λf x)), and you write the successor function that adds 1 to a number. So you call successor of zero to get one, and so on,
Just to be clear, this shouldn't actually report 3, it is just its representation?
Right. I like to use
to test work with Church numerals (which is what these things are called).
P.S. The use of the primitive + function would be cheating within the Church numeral exercise itself; it's a way of breaking the abstraction to get a human-readable result for debugging.
Thanks for the help. I know it takes a lot of time on your part, but it would be cool if you could do some 'lessons' on Church Numerals like you did with the lists.
x/y = x * y^-1
Oh, but this is a different situation. If I tell you all about it, you don't get the fun of figuring it out. All you're given is zero: (λf . (λx . x)) and successor: (λn . (λf . (λx . (f ((n f) x)) ))) which takes a number n and gives you n+1. So, convince yourself that (successor zero) is one, (successor one) is two, and so on. Then figure out how to add two numbers, how to multiply, and okay, strictly speaking you're only given functions of one input, and if you want two inputs A and B you do (λa . (λb . whatever)) but to save time and thought we'll let you say (λab . whatever) and so here's True: (λab . a) and False: (λab . b) and your job is to invent if, and then invent zero? that reports True if the input is zero and False if it's some number bigger than zero. (No negative numbers because they're all generated from zero by calling successor a bunch of times, and successor just makes things bigger.) Then invent =, which takes two numbers and says if they're equal.
Then comes the fun part, which is to invent predecessor, which takes a number n and reports n-1, unless n=0, which is an error (but you don't have to give an error message, just report whatever's convenient). And then subtraction.
Wow. Thanks for the help. I will try to play around with these when I have the time.
I’ve been trying to get lambda calculus to work too but I can’t seem to get the Y combinator to work
Hi, welcome to the forum!
I'm guessing that you're trying to use the canonical Y combinator, which depends on normal order evaluation. This Wikipedia article shows how to write Y in applicative order, which is what Snap! uses. (It's hard to read, though.)
Any way to force normal order eval?
Yes, you can set the input types of all your custom blocks' inputs to "Any(unevaluated)" and then CALL the input to evaluate it when you're ready to.
The problem is, having the application block have unevaluated inputs won’t create normal order eval, as the apply block just calls a with inputs b.
Hmm, I'll have to think about this, but when you use a computed value as the function to call, that's when you force that value -- just the function you're calling, not the ones you're using as arguments.
Hi, to expand on what Joan correctly wrote: from a maths point of view it makes sense to talk about a division operation when you have a field. Examples of fields are rationals, reals, complex, ... not integers, obviously.
And, in those settings, division as a binary operator is not the regularly chosen, cleaner way of introducing the concept. Instead, the primitive operation is a unary inverse: inv(x) = x^(-1). It exists for all elements in the field except the 0, it satisfies a series of properties, etc.
Binary multiplication and unary inverse are the primitive operators I'd choose. You can then easily define binary division on top of them as: a/b = a * inv(b)
If rings had the appearance of λabc...z.() , lambda calculus would look a lot nicer in Snap!
Yeah, as a spare time project I've been working on trying to invent a custom block like that with upvars, but I have so far been stymied by the scoping behavior of upvars.
Maybe some form of translation of the ring to lambda form?
Oh, we're not going to add syntactic sugar to Snap! for the sake of lambda calculus. But it should be possible to implement with the regular old features.