Bash Primitive Types - bash

What are the primitive types in bash scripting? I feel like this is a simple question, but it has been surprisingly hard to find the answer. I know there are at least arrays because you can do commands such as
for file in *.less
# code working with file
so that makes it appear like *.less is an array.
Also, there are string types, because if I have
a=y
b=z
c=$a+$b
echo $c
>> y+z
are there any other types besides this? Thanks a lot!
EDIT: After doing further research it also appears that there are associative arrays, which can be declared in the following manner
declare -A address
which I got from here. Are there any examples of other types?

It's an interesting question, here's what I found:
bash supports several programming primitives shared by most
programming languages. It can perform choices (if then else, case), it
can loop (for,while, until) and it has functions (function).
http://dasher.wustl.edu/chem478/software/unix-tools/bash.html
Bash variables are untyped.
Unlike many other programming languages, Bash does not segregate its
variables by "type." Essentially, Bash variables are character
strings, but, depending on context, Bash permits arithmetic operations
and comparisons on variables. The determining factor is whether the
value of a variable contains only digits.
http://tldp.org/LDP/abs/html/untyped.html
Bash provides one-dimensional indexed and associative array variables.
http://www.gnu.org/software/bash/manual/html_node/Arrays.html#Arrays

Related

Is a single constant value considered an expression?

After reading this answer on a CSS question, I wonder:
In Computer Science, is a single, constant value considered an expression?
In other words, is 7px an expression? What about just 7?
Quoting Wikipedia, emphasis mine:
An expression in a programming language is a combination of one or more explicit values, constants, variables, operators, and functions that the programming language interprets [...] and computes to produce [...] another value. This process, as for mathematical expressions, is called evaluation.
Quoting MS Docs, emphasis mine:
An expression is a sequence of one or more operands and zero or more operators that can be evaluated to a single value, object, method, or namespace. Expressions can consist of a literal value [...].
These both seems to indicate that values are expressions. However, one could argue that a value will not be evaluated, as it is already only a value, and therefore doesn't qualify.
Quoting Techopedia, emphasis mine:
[...] In terms of structure, experts point out that an expression inherently needs at least one 'operand’ or value that is acted on, and must have one or more operators. [...]
This suggests that even x does not qualify as expression as it is lacking one or more operators.
It depends on the exact definition of course, but under most definitions expressions are defined recursively with constants being one of the basis cases. So, yes, literal values are special cases of expressions.
You can look at grammars for various languages such as the one for Python
If you trace through the grammar you see that an expr can be an atom which includes number literals. The fact that number literals are Python expressions is also obvious when you consider productions like:
comparison: expr (comp_op expr)*
This is the production which captures expressions like x < 7, which wouldn't be captured if 7 isn't a valid expression.
In Computer Science, is a single, constant value considered an expression?
It depends entirely on the context. For example, FORTRAN, BASIC, and COBOL all have line numbers. Those are numeric constant values that are not expressions.
In other contexts (even within those languages) a numeric constant may be an expression.

What's a polyadic function?

There's no clear definition for a polyadic function on the internet. Please help me with a clear definition. On the other hand, there is some information about variadic functions available. Variadic functions mean that they take a variable number of arguments and apparently, such functions are supported by C.
Adic stands for number of arguments. So poly + adic means multiple number of arguments that a function can take. It will have more than 1 argument. In python you can define the arguments where you declare it. Hope that helps.
Arithmetic functions in LISP language are polyadic. ie, they can take multiple arguments.

Why is useful to have a atom type (like in elixir, erlang)?

According to http://elixir-lang.org/getting-started/basic-types.html#atoms:
Atoms are constants where their name is their own value. Some other
languages call these symbols
I wonder what is the point of have a atom type. Probably to help build a parser or for macros? But in everyday use how it help the programmer?
BTW: Never use elixir or erlang, just note it exist (also in kdb)
They're basically strings that can easily be tested for equality.
Consider a string. Conceptually, we generally want to think of strings as being equal if they have the same contents. For example, "dog" == "dog" but "dog" != "cat". However, to check the equality of strings, we have to check to see if each letter in one string is equal to the letter in the same position in another string, which means that we have to walk through each element of the string and check each character for equality. This becomes a bit more cumbersome if dealing with Unicode strings and having to consider different ways of composing identical characters (for example, the character Ă© has two representations in UTF-8).
It would be much simpler if we stored identical strings at the same location in memory. Then, checking equality would be a simple pointer or index comparison.
As a consequence of storing identical strings in the same location in memory, we can also store one copy of each unique kind of string regardless of how many times it is used in the program, thus saving some memory for commonly-used strings as well.
At a higher level, using atoms also lets us think of strings the same way we think of other primitive data types like integers.
I think that one of the most common usage in erlang is to tag variables and messages, with the benefit of fast comparison (pattern match) as mipadi says.
For example you write a function that may fail depending on parameters provided, the status of connection to a server, or any reason. A very frequent usage is to return a tuple {ok,Value} in case of success, {error,Reason} in case of error. The calling function will have the choice to manage only the success case coding {ok,Value} = yourModule:yourFunction(Param...). Doing this it is clear that you consider only the success case, you extract directly the Value from the function return, it is fast, and you don't have to share any header with yourModule to decode the ok atom.
In messages you will often see things like {add,Key,Value}, {delete,Key},{delete_all}, {replace,Key,Value}, {append,Key,Value}... These are explicit messages, with the same advantages as mentioned before: fast,sensible,no share of header...
Atoms are constants with itself as value.
This is a concept very usefull in distributed systems, where constants can be defined differently on each system, while atoms are self-containing with no need for definement.

Mapping Untyped Lisp data into a typed binary format for use in compiled functions

Background: I'm writing a toy Lisp (Scheme) interpreter in Haskell. I'm at the point where I would like to be able to compile code using LLVM. I've spent a couple days dreaming up various ways of feeding untyped Lisp values into compiled functions that expect to know the format of the data coming at them. It occurs to me that I am not the first person to need to solve this problem.
Question: What are some historically successful ways of mapping untyped data into an efficient binary format.
Addendum: In point of fact, I do know which of about a dozen different types the data is, I just don't know which one might be sent to the function at compile time. The function itself needs a way to determine what it got.
Do you mean, "I just don't know which [type] might be sent to the function at runtime"? It's not that the data isn't typed; certainly 1 and '() have different types. Rather, the data is not statically typed, i.e., it's not known at compile time what the type of a given variable will be. This is called dynamic typing.
You're right that you're not the first person to need to solve this problem. The canonical solution is to tag each runtime value with its type. For example, if you have a dozen types, number them like so:
0 = integer
1 = cons pair
2 = vector
etc.
Once you've done this, reserve the first four bits of each word for the tag. Then, every time two objects get passed in to +, first you perform a simple bit mask to verify that both objects' first four bits are 0b0000, i.e., that they are both integers. If they are not, you jump to an error message; otherwise, you proceed with the addition, and make sure that the result is also tagged accordingly.
This technique essentially makes each runtime value a manually-tagged union, which should be familiar to you if you've used C. In fact, it's also just like a Haskell data type, except that in Haskell the taggedness is much more abstract.
I'm guessing that you're familiar with pointers if you're trying to write a Scheme compiler. To avoid limiting your usable memory space, it may be more sensical to use the bottom (least significant) four bits, rather than the top ones. Better yet, because aligned dword pointers already have three meaningless bits at the bottom, you can simply co-opt those bits for your tag, as long as you dereference the actual address, rather than the tagged one.
Does that help?
Your default solution should be a simple tagged union. If you want to narrow your typing down to more specific types, you can do it - but it won't be that "toy" any more. A thing to look at is called abstract interpretation.
There are few successful implementations of such an optimisation, with V8 being probably the most widespread. In the Scheme world, the most aggressively optimising implementation is Stalin.

R6RS vs. R5RS scheme

I'm relatively new to scheme and am having a hard time finding a concrete document online overviewing the major changes that happened with R6RS. Anyone care to elaborate?
http://community.schemewiki.org/?R6RS has compiled a list of high level changes with some commentary, including:
case sensitive syntax
square brackets are now equivalent to parentheses (e.g., (let ([foo 3]) ...) - this was supported in some scheme implementations but is now part of the standard
retaining the ability to return multiple values
more escape characters in strings, e.g., "\n"
hashtables as a library
multiline and expression comments
http://www.r6rs.org/versions/CHANGES
http://www.r6rs.org/formal-comments/
http://lambda-the-ultimate.org/node/1342
If you're relatively new to scheme and have the fortitude you will get more mileage reading the spec instead of skimming a changelog though...

Resources