When a keyword means different things in different contexts, is that an example of context sensitivity? - scala

According to this answer => in Scala is a keyword which has two different meanings: 1 to denote a function type: Double => Double and 2 to create a lambda expression: (x: Double): Double => 2*x.
How does this relate to formal grammars, i.e. does this make Scala context sensitive?
I know that most languages are not context free, but I'm not sure whether the situation I'm describing has anything to do with that.
Edit:
Seems like I don't understand context sensitive grammars well enough. I know how the production rules are supposed to look, and what they mean ("this production applies only if A is surrounded by these symbols"), but I'm just not sure how they relate to actual (programming) languages.
I think my confusion stems from reading something like "Chomsky introduced this term because a word's meaning can depend on its context", and I connected => with the term "word" in the quote, and those two uses of it being two separate contexts.
It be great if an answer would address my confusion.

It's been a while since I've handled formal language theory, but I'll bite.
"Context-free" means that the production rules required in the corresponding grammar do not have a "context". It does not mean that a specific symbol cannot appear in different rules.
Addressing the edit: in other words (and more informally), deciding whether a language is context-free or context-sensitive boils down not to looking at the "meaning" of a specific "word" or "words". Instead, it amounts to looking at the set of all legal expressions in that language, and seeing whether you can "encode" them only by taking into account the positional relationships the component "words" have with one another. This is essentially what the Pumping Lemma checks.
For example:
S → Type"="Body
Type → "Double"
Type → "Double""=>""Double"
Body → Lambda
Body → NormalBody
NormalBody → "x"
Lambda -> "x""=>"NormalBody
Where S is of course the start symbol, uppercased IDs are nonterminals, and quoted strings are terminals. Obviously, this can generate a string like:
Double=>Double=x=>x
but the grammar is still context-free.
So just this, as in the observation that the nonterminal "=>" can appear in two "places" of the program, does not make Scala context-sensitive.
However, it does not mean that:
the entire Scala language is context-free,
it is context-sensitive - it can be even more complex,
if you would like to encode the semantics of Scala into a grammar, you would end up with either a context-free or a context-sensitive one.
The last thing is especially relevant since you've mentioned "meaning" in the (nomen omen) context of formal languages.

Related

What does `Control.refine` do in Ltac2?

I'm learning Ltac2 and reading the official documentation of coq 8.13.2.
I do not get what role Control.refine play in the evaluation inside of quotations, as there doesn't seem to be a lot of explanations to this function.
For example, using variables in tactic expressions inside a constr quotation should be done by: constr:(... $x ...), where $x is the syntactic sugar of ltac2:(Control.refine (fun () => x)).
Why does, say simply, ltac2:(x) not work? (and it indeed doesn't, as coq gives an error of Error: Cannot infer an existential variable of type ..., at the position where the constr represented by x should be inserted).
So my questions are:
What does Control.refine do in general?
It seems to be an idiom to sometimes do this: constr:( ... ltac2:(Control.refine (fun () => ...) ...), in what situation where such anti-quotation idiom should (or shouldn't) be used?
Thanks.
The ltac2:(...) in-term quotation expects an Ltac2 term of type unit, not of type constr. Actually, your example should trigger a warning because of this.
Since the content of the quotation has type unit, it means that it can only act through side-effects. The warning tells you that the value returned by the quotation will be discarded. In particular, it cannot be used to fill the hole.
Rather, the semantics of the quotation is to evaluate its content inside a goal Γ ⊢ A where Γ is the current list of hypotheses, and A the inferred type of the hole. It is expected that doing this will solve the goal, and the resulting partial proof will be used as the Coq term filler for that hole. This is precisely the rôle of Control.refine : (unit -> constr) -> unit. It takes a (for technical reasons, thunked) term as an argument and uses it to solve the goal(s) under focus.
What happens in your example is that you provide a term that is just ignored, the goal is left untouched and the quotation rightfully complains that it was not solved.
Regarding your second point, I cannot really tell. It depends on what you want do do. But in general, if you stick to antiquotations $x I would consider this more readable. It is not always possible to do so, though, e.g. if the term being built depends on a context introduced in the constr:(...) quotation.

Is Racket (and Typed Racket) strongly or softly typed?

I realize the definitions of "strongly typed" and "softly typed" are loose and open to interpretation, but I have yet to find a clear definition in relation to untyped Racket (which from my understanding means dynamically typed) and Typed Racket on this.
Again, I'm sure its not so cut and dry, but at least I'd like to learn more about which direction leans in. The more research I've done of this the more confused I've gotten, so thank you in advance for the help!
One problem in answering questions like this is that people disagree about the meanings of nearly all of these terms. So... what follows is my opinion (though it is a fairly well-informed one, if I do say so myself).
All languages operate on some set of values, and have some runtime behavior. Trying to add a number to a function fails in nearly all languages. You can call this a "type system," but it's probably not the right term.
So what is a type system? These days, I claim that the term generally refers to a system that examines a program and statically[*] deduces properties of the program. Typically, if it's called a type system, this means attaching a "type" to each expression that constrains the set/class of values that the expression can evaluate to. Note that this definition basically makes the term "dynamically typed" meaningless.
Note the giant loophole: there's a "trivial type system", which simply assigns the "type" containing all program values to every expression. So, if you want to, you can consider literally any language to be statically typed. Or, if you prefer,
"unityped" (note the "i" in there).
Okay, down to brass tacks.
Racket is not typed. Or, if you prefer, "dynamically typed," or "unityped," or even "untyped".
Typed Racket is typed. It has a static type system that assigns to every expression a single type. Its type system is "sound", which means that evaluation
of the program will conform to the claims made by the type system: if Typed Racket
(henceforth TR) type-checks your program and assigns the type 'Natural' to an
expression, then it will definitely evaluate to a natural number (assuming no bugs
in the TR type checker or the Racket runtime system).
Typed Racket has many unusual characteristics that allow code written in TR to interoperate with code written in Racket. The most well-known of these is "occurrence typing", which allows a TR program to deal with types like (U Number String) (that is, a value that's either a number or a string) without exploding, as earlier similar type systems did.
That's kind of beside the point, though: your question was about Racket and TR, and the simple answer is that the basic Racket language does not have a static type system, and TR does.
[*] defining the term 'static' is outside the scope of this post :).
Strongly typed and weakly typed has nothing to do with static or dynamic typing. you can have a combination of them so that you have 4 variations. (strong/static, weak/static, strong/dynamic, weak/dynamic).
Scheme (and thus #lang racket) are dynamicaly and stronged typed.
> (string-append "test" 5)
string-append: contract violation
expected: string?
given: 5
argument position: 2nd
other arguments...:
All it's values have a type and the functions can demand a type. If you were to append a string to a number you get a type error. you need to explicitly cast the number to a string using number->string to satisfy the contract of all arguments being strings. With weakly typed languages, like JavaScript, it would just cast the number to a string so satisfy the function. Less code, but possibly more runtime bugs.
Since Scheme is strongly typed #lang typed/racket is definitely too.
While Scheme/#lang racket is dynamicly typed I'm not entirely sure if #lang typed/racket is completely static. The Guide calls it a gradually-typed language.
One of the definitions of "weakly typed" is that when there is a type mismatch between operands instead of giving an error the language will try its best to continue, by coercing the operands from one type to the other or giving a default result.
For example, in Perl a string containing digits will be coerced into a number if you use it in an arithmetic operation:
# This Perl program prints 6.
print 3 * "2a"
Under this definition, Racket would be categorized a dynamically typed (type errors occur at runtime) and strongly typed (it doesn't automatically convert values from one type to the other).
Since Typed Racket doesn't change the runtime semantics of Racket (except by introducing some extra contract checking) it would be just as strongly typed as regular Racket.
By the way, the usual words people use are weak and strong typing. Soft typing might refer to one specific kind of type system that was created during the 90s. It didn't turn out all that well, which is one of the reasons that people come up with the Gradual Typing system that is used in languages such as Typed Racket and Typescript.
Weakly typed language allows a legal implementation to set computer "on fire", in contrast, strongly typed language limits more buggy programs.
In spite of Racket is dynamically typed, it is strongly typed.

Want to distinguish between value and expression

I'd like to know how I can distinguish between 'value' and 'expression'.
In computer science, a value is an expression which cannot be
evaluated any further (a normal form).[1] The members of a type are
the values of that type.[1] For example, the expression 1 + 2 is not a
value as it can be reduced to the expression 3. This expression cannot
be reduced any further (and is a member of the type Nat) and therefore
is a value.
I found a statement above from the url below:
https://en.wikipedia.org/wiki/Value_(computer_science) 2
From this statement I felt like:
I think "value" look like the "atom" in chemistry based upon the
definition of Mitchell, John C.
But someone denied this:
But, even expressions can be (represented as) values. The classic case
being an s-expression in Lisp-like languages. – user2864740
This talk is in another thread : what-is-the-value-in-1st-class-value 3
It would have been so simple if user2864740 didn't say anything. But he said so and I am confused.
Could someone explain me about this situation? or the difference that might exist in lisp like languages?
Thank you in advance!
[1] Mitchell, John C. (1996). Foundations for Programming Languages. The MIT Press.
If you don't know Lisp, read SICP and play with some Scheme implementation.
(the classic SICP book is a must read -it is a very good introductory book about programming-, so even if you know Lisp but didn't read SICP you really should read it; and it is freely available on-line.)
I strongly recommend reading C.Queinnec's Lisp In Small Pieces book, which explains how LISP interpreters or compilers expressions are designed, so cover your question is great details.
(actually your question needs an entire book to be answered, and Queinnec's book is that book)
LISP is an homoiconic language, hence s-expressions are values (but several values are not expressions, in particular closures). But most programming languages -C, Ocaml, Javascript, C++, Java, etc...- are (sadly) not homoiconic: their AST is not a value and expressions cannot manipulate ASTs natively.
BTW, the wikipedia sentence
a value is an expression which cannot be evaluated any further
is not always correct. For example, for the C language, values and expressions are different kind of beasts.
You should also read something about formal semantics of programming languages.
Also, reading Scott's Programming Language Pragmatics will give you a broader view (thru several programming languages).
A value is a datum: the machine representation of some piece of information, such as a number or character string. The datum belongs to a type which has an associated domain: as set of all possible values of that type. The value is an element of that set.
An expression is a datum which represents syntax: usually a structured datum build as an aggregate (usually a tree structure) of other values. However, an individual non-aggregated value can also be an expression.
The purpose of an expression may be to denote the computation of a value; in that situation, ANSI Common Lisp refers to an expression as a form. Not all expressions are forms. For instance in (let ((a 42))), (a 42) is an expression denoting, in the context of let, the variable a and its initializing form 42, and ((a 42)) is an expression denoting the complete list of binding specifications under that let.
If a form is evaluated, and the result is a datum similar to that form itself, then one of the two is the case: the form might be a literal (a value which evaluates to itself if it is treated as an expression) or it might be a quine: a clever form which doesn't directly yield itself as a value (the way a literal does) but cleverly calculates an object which is structurally identical to itself.
A value is not defined as an expression which is irreducible and denotes itself; that is a literal constant. A literal constant denotes a value. Values, however, exist in all contexts, such as the run-time context in which syntax is no longer relevant. When a program is running, it can instantiate values which never exist as a piece of syntax. If we evaluate (+ 2 2), there is a 4 which never appeared in the syntax as the expression 4. Therefore we cannot say that the value 4 is an expression which is irreducible; the value exists even if no such expression does.

Functional programming: Curry & Fold - what are the etymologies?

Curry & Fold - what are the etymologies in the programmatic sense?
I do not see how any of the English meanings of these homonyms is related to the functionality of these terms.
If you had to rename them to something more obvious - how would you do it?
Curry is the last name of Haskell Curry, a prominent 20th century logician after whom Haskell got its name.
And "folding" simply because the fold operator figuratively represents folding, like a hand of cards can be folded to look like a single card. Think of foldr (+) 0 [1,2,3] == 6 as a hand of cards 1, 2 and 3 folded into a single card 6.
The word "reducing", which also means folding, can be illustrated using a similar analogy.
Of course, Haskell is more magic than even the bluffiest and luckiest game of poker, so folds in functional programming can actually produce a deck of cards that holds more cards than the hand it was folded from, or cards can be folded into cats, etc: foldr (\i, acc -> [show i,show i,show i] ++ acc) [] [1,2,3] == ["1","1","1","2","2","2","3","3","3"]. Therefore what started out as folding eventually evolved into an extremely universal operator that can produce map as well as filter etc, so don't get too carried away with the poker comparison and etymology.
As to what to name them to: renaming a dead person might not be the most ethical thing to do. The poor guy is so successful BOTH of his names are used for big things, and then you want to deprive him posthumously of his joy and rename him to something else? Unless perhaps that something else is Newton Watt Scoville or Kelvin Celsius Ângström, I'd seriously not attempt a rename.
However if you meant renaming the programming concept: it could instead be referred to by the name "ricing" in my hungry opinion. But Mr. Curry might still feel intimidated.
Folding could actually be renamed to bluffing, if you're not fulfilled by the multitude of presently available names for it — thanks to som-snytt for the constructive idea.
I believe that the "fold" term comes mainly from the use of the word "fold" in phrases like "to fold into..." which is a term most commonly used by chefs, I believe (I watch a lot of cooking shows...). We use it in the context of functional programming because we say that, for example, for lists, the head of the list is "folded into" the resulting of folding the tail. For example, the function foldr is a "recipe" for how to "cook" a list, and part of that recipe is "fold this into that", if you like.
The oldest reference to "folding" that I could find on the internet in the context of functional programming in this report, published in 1985 by the University of Cambridge, which has this to say:
The function gather applies a function of two arguments “between” each element of a list and a terminal value. [...] This function is also known as reduce or fold in other languages.
So clearly the term "fold" was at least somewhat common even 30 years ago!

Using match with user defined types in PL Racket

The following PL code does not work under #lang pl:
Edited code according to Alexis Kings answer
(define-type BINTREE
[Leaf Number]
[Node BINTREE BINTREE])
(: retrieve-leaf : BINTREE -> Number)
(define (retrieve-leaf btree)
(match btree
[(Leaf number) number])
What i'd like to achieve is as follows:
Receive a BINTREE as input
Check whether the tree is simply a leaf
Return the leaf numerical value
This might be a basic question but how would I go about solving this?
EDIT: The above seems to work if cases is used instead of match.
Why is that?
As you've discovered, match and cases are two similar but separate
things. The first is used for general Racket values, and the second is
used for things that you defined with define-type. Unfortunately,
they don't mix well in either direction, so if you have a defined type
then you need to use cases.
As for the reason for that, it's kind of complicated... One thing is
that the pl language was made well before match was powerful enough
to deal with arbitrary values conveniently. It does now, but it cannot
be easily tweaked to do what cases does: the idea behind define-type
is to make programming simple by making it mandatory to use just
cases for such values --- there are no field accessors, no predicates
for the variants (just for the whole type), and certainly no mutation.
Still, it is possible to do anything you need with just cases. If you
read around, the core idea is to mimic disjoint union types in HM
languages like ML and Haskell, and with only cases pattern matching
available, many functions are easy to start since there's a single way
to deal with them.
match and Typed Racket got closer to being able to do these things,
but it's still not really powerful enough to do all of that --- which is
why cases will stay separate from match in the near future.
As a side note, this is in contrast to what I want --- I know that this
is often a point of confusion, so I'd love to have just match used
throughout. Maybe I'll break at some point and hack things so that
cases is also called match, and the contents of the branches would
be used to guess if you really need the real match or the cases
version. But that would really be a crude hack.
I think you're on the right track, but your match syntax isn't correct. It should look like this:
(: retrieve-leaf : BINTREE -> Number)
(define (retrieve-leaf btree)
(match btree
[(Leaf number) number]))
The match pattern clauses must be inside the match form. Additionally, number is just a binding, not a procedure, so it doesn't need to be in parens.