feat(archives): transfer locally, instead of fetching from git

This commit is contained in:
Jean-Philippe Sirois
2019-11-21 03:48:34 -05:00
parent 9f6e420a44
commit 0bc9d6b3df
9 changed files with 861 additions and 63 deletions
+2 -3
View File
@@ -64,11 +64,10 @@ module.exports = {
}, },
}, },
{ {
resolve: `gatsby-source-git`, resolve: `gatsby-source-filesystem`,
options: { options: {
name: `what-is-archive`, name: `what-is-archive`,
remote: `https://github.com/the-programmers-hangout/technology-spotlight`, path: `${__dirname}/src/content/archives`,
patterns: [`*.md`, `!README.md`],
}, },
}, },
`gatsby-transformer-sharp`, `gatsby-transformer-sharp`,
-59
View File
@@ -9541,39 +9541,6 @@
} }
} }
}, },
"gatsby-source-git": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/gatsby-source-git/-/gatsby-source-git-1.0.2.tgz",
"integrity": "sha512-TNCC8PnRK3knrO5Q9qpOWVsYuRuLZ07LGB2kQw4/b4bmbciVFZSNUfuJpokpl3/6DPvcePQtNjARVpdKrRYhog==",
"requires": {
"fast-glob": "^2.2.3",
"fs-extra": "^5.0.0",
"gatsby-source-filesystem": "^2.1.19",
"git-url-parse": "^11.1.1",
"rimraf": "^2.6.2",
"simple-git": "^1.105.0"
},
"dependencies": {
"fs-extra": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
"integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==",
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"requires": {
"glob": "^7.1.3"
}
}
}
},
"gatsby-telemetry": { "gatsby-telemetry": {
"version": "1.1.33", "version": "1.1.33",
"resolved": "https://registry.npmjs.org/gatsby-telemetry/-/gatsby-telemetry-1.1.33.tgz", "resolved": "https://registry.npmjs.org/gatsby-telemetry/-/gatsby-telemetry-1.1.33.tgz",
@@ -9873,14 +9840,6 @@
"parse-url": "^5.0.0" "parse-url": "^5.0.0"
} }
}, },
"git-url-parse": {
"version": "11.1.2",
"resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.2.tgz",
"integrity": "sha512-gZeLVGY8QVKMIkckncX+iCq2/L8PlwncvDFKiWkBn9EtCfYDbliRTTp6qzyQ1VMdITUfq7293zDzfpjdiGASSQ==",
"requires": {
"git-up": "^4.0.0"
}
},
"github-from-package": { "github-from-package": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
@@ -16821,24 +16780,6 @@
} }
} }
}, },
"simple-git": {
"version": "1.126.0",
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.126.0.tgz",
"integrity": "sha512-47mqHxgZnN8XRa9HbpWprzUv3Ooqz9RY/LSZgvA7jCkW8jcwLahMz7LKugY91KZehfG0sCVPtgXiU72hd6b1Bw==",
"requires": {
"debug": "^4.0.1"
},
"dependencies": {
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"simple-swizzle": { "simple-swizzle": {
"version": "0.2.2", "version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
-1
View File
@@ -44,7 +44,6 @@
"gatsby-remark-auto-headers": "^1.0.3", "gatsby-remark-auto-headers": "^1.0.3",
"gatsby-remark-katex": "^3.1.15", "gatsby-remark-katex": "^3.1.15",
"gatsby-source-filesystem": "^2.1.33", "gatsby-source-filesystem": "^2.1.33",
"gatsby-source-git": "^1.0.2",
"gatsby-transformer-remark": "^2.6.30", "gatsby-transformer-remark": "^2.6.30",
"gatsby-transformer-sharp": "^2.3.0", "gatsby-transformer-sharp": "^2.3.0",
"katex": "^0.11.1", "katex": "^0.11.1",
+72
View File
@@ -0,0 +1,72 @@
**What is Docker?**
Docker is a platform for developers and sysadmins to develop, deploy, and run applications with containers. Containers allow for total application and environment isolation which makes it much easier to ensure an application runs with any necessary dependencies.
**Why should I use Docker?**
The simplest use case for Docker is packaging an application into an image and then running it on any machine running the Docker platform. Think running your API locally on Windows, on your OSX laptop, or on a Linux server in a cloud without making any changes to your codebase, all with the same command.
For more complex deployments consisting of multiple containers, Docker provides a tool called docker-compose. This will read a configuration of one or more Docker containers and run them for you and manage them as a single application.
Another benefit is using it to perform builds or development on local machines to avoid needing to set up a development environment. As dependencies can be a nightmare in situations like this, requiring things like npm or virtualenv and other isolation techniques, containerization can greatly simplify things and shorten the time it takes for someone to get set up on a project. You can even pull down a container containing a language runtime and just start writing code immediately, for languages with REPLs you can use docker to launch a REPL shell for any language without needing to go install a runtime on your machine.
**What's the difference between Docker and a VM?**
VMs have been widely used to solve these problems. The key difference between VMs and containers is that containers are not a virtual OS. All containers running on a host share the same parent kernel. Container technology is enabled by core Linux kernel features for isolating applications. When you run a Linux container on a Windows machine using Docker for Windows, a single Linux VM must run as the host for the Linux containers, but when running natively on a Linux machine, no VM is required, and container applications run inside an isolated process, just like any other application.
The advantage to this approach is that it's very lightweight since it doesn't require the overhead of a virtual guest operating system and virtual access to resources through a hypervisor.
**Examples**
You can get a fully functional ubuntu machine by just running
```
docker run -it ubuntu bash
```
Running an nginx web server can be done easily using docker-compose:
docker-compose.yml:
```yml
web:
image: nginx
volumes:
- ./mysite.template:/etc/nginx/conf.d/mysite.template
ports:
- "8080:80"
environment:
- NGINX_HOST=foobar.com
- NGINX_PORT=80
command: /bin/bash -c "envsubst < /etc/nginx/conf.d/mysite.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
```
`docker-compose up -d`
You can start a Redis instance like this:
```
docker run --name my-redis -d redis
```
Then you can inspect the running containers with:
```
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d295137f5965 redis "docker-entrypoint.s…" 6 seconds ago Up 5 seconds 6379/tcp my-redis
```
and attach to the running redis container to run commands with redis-cli:
```
$ docker exec -it my-redis redis-cli
127.0.0.1:6379> set example-key 1234
OK
127.0.0.1:6379> get example-key
"1234"
```
**Resources**
- The official get-started guide: https://docs.docker.com/get-started/
- The public Docker registry: https://hub.docker.com/explore/
- Awesome Docker (a collection of Docker resources): https://github.com/veggiemonk/awesome-docker
- An example application development environment using Docker: https://www.masterzendframework.com/docker-development-environment/
+116
View File
@@ -0,0 +1,116 @@
**What is Elixir?**
Elixir is a dynamically typed, functional programming language, with an emphasis on concurrency.
Elixir, despite being a young language, has grown quite rapidly, and has surprisingly fleshed out libraries and documentation.
On a surface level, the language was inspired by ruby in terms of syntax, but the way the language works is quite different.
Elixir leverages concurrency via the "actor model", where many lightweight processes (not OS processes) are run at the same time, and manage diferent aspects of a program.
To do this, Elixir compiles to the BEAM / Erlang VM, which was built with this kind of distributed programming model in mind. Elixir is very similar in features to Erlang.
**What is Erlang?**
Erlang is a much older programming language, for which the Erlang VM was designed. Erlang was initially conceived of at Ericsson, for use in telecommunications. They needed to be able to handle many different calls at once, and so needed a programming model that support many different workers, or "actors" running concurrently.
The Erlang VM leverages the actor model to do this.
**How is Elixir different from Erlang?**
Elixir has an arguably friendlier syntax, but for the most part is very similar to erlang in terms of language constructs.
One major addition to the language however is metaprogramming. Elixir has a rich and easy to use macro system, and an almost homiconic syntax, somewhat reminiscent of Lisp, but without the parens. Elixir also comes with a somewhat richer standard library. Another big advantage of Elixir is very easy interop with Erlang: calling an Erlang function is as simple as calling an Elixir one, and Erlang users can also use Elixir functions with little pain.
**What is the actor model?**
We've mentioned the actor model a few times, but what exactly is it?
The actor model is 2 things
1. Lightweight processes in which code can run
2. Ways to communicate between processes
In elixir / erlang, we can run millions of processes concurrently with no worry at all. Each process has its own memory and resources, and to share these, they must communicate. Communication via processes is done via "message passing" where a process A will send a message to another process B, ready to receive and respond to that message. The only way to share data is by communicating, no 2 processes can hold onto the same piece of memory. This model avoids many problems arising from shared concurrent state (though not all, mind you).
**How do I learn more about Elixir?**
There's quite a few resources on Elixir, including a few books https://elixir-lang.org/learning.html#books.
A good place to start if you're interested is the website itself: https://elixir-lang.org/ which includes a lot of information about the language, including a guide to installing and getting started with it, as well as a large tutorial guiding you through most of the language's constructs.
Another tutorial series that goes a bit more in depth is: https://elixirschool.com/en/, which I used when learning the language myself.
**Code Examples**
**A Simple Hello World**
```elixir
IO.puts "Hello World from Elixir!"
```
**Various ways of summing a lists**
The first works via recursion and pattern matching on the shape of a list, the second works by using a function defined in the Enum module.
```elixir
defmodule Sums do
def sum_list([], acc) do
acc
end
def sum_list([head | tail], acc) do
sum_list(tail, head + accumulator)
end
def sum_list2(list) do
Enum.reduce(list, fn x, acc -> x + acc end)
end
end
```
**Concurrent Processes**
A simple example how simple processes can delegate work between eachother. The different processes here are running in parallel after being spawned.
```elixir
defmodule Dialogue do
def printer do
receive do
{:msg, msg} -> IO.puts msg
end
end
def person(my_name, printer_id) do
receive do
{:hello, name, address} ->
send(printer_id, {:msg, "I got a message from #{name}"})
send(address, {:hello, my_name, self()})
end
end
def run_dialogue do
printer_id = spawn(printer)
joe = person("Joe", printer_id)
send(joe, {:hello, "Omniscient Programmer", self()})
end
end
```
**A concurrent Key/Value store**
```elixir
defmodule Store do
def store(map) do
new_map = receive do
{:put, k, v, callback} ->
new = Map.put(map, k, v)
send(callback, :success)
new
{:get, k, callback} ->
v = Map.get(map, k)
send(callback, {:success, v})
map
end
store(new_map)
end
def run_store do
store_id = spawn(fn -> store(%{}) end)
send(store_id, {:put, "North Pole", "Santa", self()})
send(store_id, {:get, "North Pole", self()})
# Santa should be printed
receive do
{:success, v} -> IO.puts(v)
end
end
end
```
+176
View File
@@ -0,0 +1,176 @@
**What is GraphQL?**
GraphQL is a query language for APIs, meant to challenge and replace REST. At its core, GraphQL enables declarative data fetching where a client can specify exactly what data it needs from an API. Put bluntly, a lot of people claim GraphQL to be REST 2.0.
**Why does GraphQL exist?**
GraphQL was created internally by Facebook in 2012, mainly to optimize the network load for mobile devices. Interestingly, other companies like Netflix or Coursera were working on comparable ideas to make API interactions more efficient. When Facebook announced GraphQL, Coursera abandoned their efforts and jumped on GraphQL.
**What makes GraphQL better than REST?**
1. GraphQL resolves the issues of underfetching, and overfetching of REST. For example, if you were to retrieve a user, its name, and the title of his posts, REST would end up over and under fetching this :
```
/users/5
/users/5/posts
```
```js
// REST return for endpoint /users/5
{
id: 5,
name: "veksen",
email: "[email protected]",
role: "Chat Mod",
permissions: ["readThis", "writeThat"],
dob: "1970/01/01",
location: "Montreal"
}
// REST return for endpoint /users/5/posts
[
{ id: 3, title: "My first post", content: "The full content of the post, possibly a few Ks of data" },
{ id: 7, title: "GraphQL is pretty neat", content: "The full content of the post, possibly a few Ks of data" },
{ id: 8, title: "GOTO considered harmful", content: "The full content of the post, possibly a few Ks of data" }
]
```
Meanwhile, a GraphQL query would look like :
```
query user(id: "5") {
id
name
posts {
id
title
}
}
```
```js
// GraphQL return for our query
{
id: 5,
name: "veksen",
posts: [
{ id: 3, title: "My first post" },
{ id: 7, title: "GraphQL is pretty neat" },
{ id: 8, title: "GOTO considered harmful" }
]
}
```
2. GraphQL helps building features faster. Because of the way the front-end can explicitly query the data it needs, it's not rare to not need to update the backend API. Again, using the example from earlier, if we wanted to also fetch the user friends, we could simply add it to our query:
```
query user(id: "5") {
name
posts {
title
}
friends {
firstName
lastName
}
}
```
3. Strong-typing. Contrary to working with JSON responses limited to string and numeric, and the discrepancy between front-end (JS) and any back-end language being lost in translation.
**Core concepts**
GraphQL has three types of operations:
- queries (fetching data),
- mutations (creating/updating/deleting data),
- subscriptions (real-time listeners to data changes, using websockets behind the hood).
Basic query:
```
query User($id: ID) {
user {
id
role
permissions {
name
}
}
}
```
Basic mutation:
```
mutation CreatePost($title: String!, $content: String!, $draft: Boolean!) {
createPost(title: $title, content: $content, draft: $draft) {
title
content
draft
}
}
```
Basic subscription:
```
subscription OnMessageReceived($conversationId: ID!){
messageReceived(conversationId: $conversationId){
id
content
}
}
```
At its core, GraphQL consists of two parts: client, and server.
A server contains a single endpoint, accepting GET and POST requests, which are translated like so:
```
{
me {
name
}
}
```
becoming:
```
http://myapi/graphql?query={me{name}}
```
**How can I start using GraphQL?**
While it is possible to convert an existing REST endpoint to GraphQL, either through automated tools, or manually, the best case scenario would be on an entirely new project.
**Common misconceptions**
- Because the query is explicit, a lot of people think that GraphQL is unsafe, making all of the data available to anyone. GraphQL is bound to the same safety procedures that a regular API would: permissions are defined by the backend.
- GraphQL is a query language for APIs, not databases! This means it can be used with any database. The API is responsible for converting the query to a database query.
- When it was first announced by Facebook, a lot of people thought it was React exclusive! This is not true. GraphQL can work on any tech stack (although some languages have more complete tooling than others)
**Closing notes**
Today, GraphQL is used in production by lots of different companies such as GitHub, Twitter, Yelp and Shopify - to name only a few. We are seeing month after month, small and large companies converting to it.
**Related projects and libraries**
- Apollo (GraphQL server + client) <https://www.apollographql.com/>
- Relay (GraphQL client) <https://facebook.github.io/relay/>
- Prisma (GraphQL server with ORM-like DB queries to MySQL + Postgres) <https://www.prisma.io/>
- PostGraphile (GraphQL API from a Postgres schema) <https://www.graphile.org/postgraphile/>
- Hasura (GraphQL server to Postgres mapping service) <https://hasura.io/>
- GraphCMS <https://graphcms.com/>
- Graphene JS & Python <http://graphene-js.org/> <http://graphene-python.org/>
**Attached resources**
- Full-stack introduction to GraphQL: <https://www.howtographql.com/>
- Zero to GraphQL in 30m: <https://www.youtube.com/watch?v=UBGzsb2UkeY>
- GraphQL Community Resources: <https://graphql.org/community/>
- GraphQL intro: <https://graphql.org/learn/>
- Awesome GraphQL: <https://github.com/chentsulin/awesome-graphql>
**Example codebase**
- Airbnb Clone server (NodeJS): <https://github.com/prismagraphql/graphql-server-example>
- E-commerce full-stack (React+NodeJS) <https://github.com/KATT/shop>
+39
View File
@@ -0,0 +1,39 @@
**What is Haskell?**
"Haskell is a computer programming language. In particular, it is a polymorphically statically typed, lazy, purely functional language, quite different from most other programming languages. The language is named for Haskell Brooks Curry, whose work in mathematical logic serves as a foundation for functional languages. Haskell is based on the lambda calculus, hence the lambda we use as a logo." - Haskell Wiki
The above being said, if you perceive yourself to be "bad" at math, don't feed into it. If you are interested in using it and you apply yourself it will work out.
**Why should I use Haskell?**
Haskell is a general purpose programming language. So you can use it for anything, from scripting to game development - that being said, it provides you with some rather unique and cool benefits not found in many other places.
- Haskell code tends to be very short and clear (See code examples below)
- Since it is very, very high level, the language is incredibly expressive (See DSL below)
- Concurrency is much better in Haskell than in many other languages (See here: https://en.wikibooks.org/wiki/Haskell/Concurrency)
- The type system is exceptionally good. Certain types of errors cease to exist (e.g. no Null pointer exception) (See here: https://softwareengineering.stackexchange.com/questions/279316/what-exactly-makes-the-haskell-type-system-so-revered-vs-say-java?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa )
- Purity. Haskell _does not allow for side affects_. In other languages, a "getMember" function might get you a member, might not. But it might also scrape a key up the side of your car. This kind of problem is not possible in Haskell thanks to purity. (See here: https://wiki.haskell.org/Functional_programming#Purity)
**Code Examples**
Fizzbuzz
```hs
fizzBuzz :: Integer -> String
fizzBuzz n | n `mod` 15 == 0 = "FizzBuzz"
| n `mod` 5 == 0 = "Fizz"
| n `mod` 3 == 0 = "Buzz"
| otherwise = show n
```
An infinite list of Fibonacci numbers
```hs
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
```
An infinite list of prime numbers
```hs
primes :: [Integer]
primes = sieve (2 : [3, 5..])
where
sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]
```
+159
View File
@@ -0,0 +1,159 @@
**What is kotlin?**
Kotlin is a statically typed programming language that runs on the JVM (Java Virtual Machine).
**Why does kotlin exist?**
Kotlin exists as a modern roll of Java - Java was built from the ground up to suit OOP, and that's a task that it does pretty well. Later, functional programming was added in, by contrast, kotlin was made with both paradigms in mind, picking the good, easy to adopt parts up and adding them all into one neat language. Kotlin also had a requirement: Allow interop with Java code - to which it does (works great on android!)
**How hard is kotlin to learn?**
Well, that depends a lot on where you are coming from. If you already know Java, it'll be exceptionally easy to pick up. Everything has a very "right" feeling to it compared to the older style, it's almost like a natural progression.
If you don't know Java, that's a bit trickier to answer. You can certainly learn it, as a first language either, but there are some Java things you will need to know. If I were learning it as a first language, I'd try to heavily rely on the documentation and understand each feature that exists in kotlin, and why they exist. The most important is the concept of nullable types.
Java will allow anything to be null, but in kotlin there is a distinct separation. a `String` is very different to a `String?` - the second one can have a value of null, the first cannot. When interoping with Java code, it's always best to assume anything can be null.
**What are some key features of kotlin?**
If you're a Java user, here is a comparison list made by Jetbrains: <https://kotlinlang.org/docs/reference/comparison-to-java.html>
Some key ones to point out of this list:
- Data classes (like Lombok data clases, for you java users)
- Delegation properties (Lazy evaluation, observables and more !!)
- Extension functions - great for fixing up a library class that is missing a method. No pretty print function? That's cool, just define it yourself. `LibraryClass.newFunction() = ...` (Yes, like C#)
**What platforms can kotlin run on?**
Anything and everything. Let's break that down:
**The JVM**
This is primary compile target, the JVM as a piece of kit allows you to write some code and have it work without separate compilations on Windows, Mac and Linux - so you've got all of your bases covered there.
**Android**
Yea, it's also a first class language on android, the only other language supported by google: <https://youtu.be/d8ALcQiuPWs>
**Native**
If you don't like the JVM and you're not an android dev, well, you can just target native: <https://kotlinlang.org/docs/reference/native-overview.html>
**JavaScript**
Yea, you can make kotlin compile to JavaScript, see here: <https://kotlinlang.org/docs/tutorials/javascript/kotlin-to-javascript/kotlin-to-javascript.html>
Here are some extra points that don't fit into any of the headings above
- Kotlin offers a really nice editor, Intellij - you can use the community edition for free or pay for the ultimate one, both are great.
- Kotlin is backed by 2 big companies, Jetbrains and Google, so it has a lot of life blood in it.
- Kotlin has extremely good concurrency support, see here: <https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide>.
- Kotlin is fairly unopinionated, so if you're more a functional person you can go down that route most of the way, and the same for OOP, think of it as the Jack of all trades
- Kotlin allows building through both maven and gradle, two very mature build systems with a lot of libraries available - that means that you don't need to suffer the problems associated with small languages (No tools or libraries, it already has a great set of tools (intellij, maven, gradle) and a great ecosystem (it steals from Java!))
**Learning resources**
- Language reference: <https://kotlinlang.org/docs/reference/>
- Introduction to kotlin <https://youtu.be/X1RVYt2QKQE>
- Kotlin books <https://kotlinlang.org/docs/books.html> - Pick your poison based on what it is you wanna do!
- Kotlin koans <https://kotlinlang.org/docs/tutorials/koans.html>
- Try it out online <https://try.kotlinlang.org/#/Examples/Hello,%20world!/Simplest%20version/Simplest%20version.kt>
- **Awesome** kotlin - <https://github.com/KotlinBy/awesome-kotlin> Many great resources and libraries here
**Hello, world!**
```kotlin
fun main(args : Array<String>) {
println("Hello, world!")
}
```
**FizzBuzz**
```kotlin
fun main(args: Array<String>) {
for (i in 1..100) {
println(if (i % 15 == 0) "FizzBuzz" else if (i % 3 == 0) "Fizz" else if (i % 5 == 0) "Buzz" else i)
}
}
```
**Generate some nice HTML**
```kotlin
//declarations here `https://kotlinlang.org/docs/reference/type-safe-builders.html`
import com.example.html.*
fun result(args: Array<String>) =
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
// an element with attributes and text content
a(href = "http://kotlinlang.org") {+"Kotlin"}
// mixed content
p {
+"This is some"
b {+"mixed"}
+"text. For more see the"
a(href = "http://kotlinlang.org") {+"Kotlin"}
+"project"
}
p {+"some text"}
// content generated by
p {
for (arg in args)
+arg
}
}
}
```
**Create some SQL tables and do some CRUD operations with kotlin exposed (link here: <https://github.com/JetBrains/Exposed>)**
```kotlin
// Declare the table structure
object Users : Table() {
val id = varchar("id", 10).primaryKey()
val name = varchar("name", length = 50)
val cityId = (integer("city_id") references Cities.id).nullable()
}
//Declare another table
object Cities : Table() {
val id = integer("id").autoIncrement().primaryKey() // Column<Int>
val name = varchar("name", 50) // Column<String>
}
fun main(args: Array<String>) {
Database.connect("jdbc:h2:mem:test", driver = "org.h2.Driver")
transaction {
//make em
create (Cities, Users)
val saintPetersburgId = Cities.insert {
it[name] = "St. Petersburg"
} get Cities.id
val munichId = Cities.insert {
it[name] = "Munich"
} get Cities.id
Cities.insert {
it[name] = "Prague"
}
Users.insert {
it[id] = "andrey"
it[name] = "Andrey"
it[cityId] = saintPetersburgId
}
Users.deleteWhere{Users.name like "%thing"}
println("All cities:")
for (city in Cities.selectAll()) {
println("${city[Cities.id]}: ${city[Cities.name]}")
}
}
```
+297
View File
@@ -0,0 +1,297 @@
**What is Lisp?**
Originally specified in 1958, Lisp is the second oldest high level programming language in use today. (Only younger than FORTRAN by one year!). There have been many different dialects of Lisp that have come and gone over the ages. In the modern day, some of the most known and used Lisp dialects (lisps) are Common Lisp, Clojure/ClojureScript, Racket and Scheme. The name "Lisp" was derived from "LISt Processor", and the list data structure is at the core of the language. Many recognizable language features were first developed in Lisp; dynamic typing, garbage collection, the read-eval-print loop, and more.
**How hard are Lisps to learn?**
The basics are not very difficult (especially because there aren't that many basics to learn). Experience with functional programming translates well. Most Lisps have a very small set of keywords and syntax rules, and rich libraries constructed atop those simple essentials. A lot of newcomers to Lisps are initially put off by a lot of parentheses, but most of those newcomers come to accept, and in some cases, admire the simplicity provided by, those parens. For example, Lisps usually have no concept of 'operator precedence' - the innermost parens are evaluated first.
If you know python, this document may be of particular interest to you: http://norvig.com/python-lisp.html. Even if you don't know python, the second paragraph under the heading "Introducing Python" explains some Lisp philosophy of use.
**What are some key features?**
- Homoiconicity: Lisps treat data and code similarly - that is to say, the code you write is in the form of lisp data structures (arbitrarily nested lists) that the lisp interpreter reads and evaluates. While this can feel awkward at first, it allows for what might be the simplest metaprogramming constructs.
- Macros: Macros let you expand and redefine the syntax of the language itself. Think of it as having a hook into the interpreter... you get to write what feel like functions that return lisp expressions, and the interpreter will expand those macros, and then evaluate the code that the macro expands to. This is only possible because lisp code is written as s-expressions (lists enclosed in parens). As a result, you don't find any grunt-work in lisp. No need to type semi-similar chunks of code over and over again when you can just invent new syntax for it. How powerful are macros? As one example, Clojure's function and macro definition operators are both macros that use the 'special form' (roughly a keyword) "def".
- REPL: Some dialects emphasize this more than others, but REPL-based development can provide an accelerated feedback loop.
- Other key features can vary between lisps, and sometimes even within one lisp (for example, Clojure and Racket are both "fundamentally" dynamically-typed, but they have capabilities for enabling type declarations and compile-time type checking).
Some Dialect-specific features and philosophy:
- Common Lisp:
- Multi-paradigm. Fairly liberal/unopinionated.
- Can write in an imperative style, functional, OOP, whatever. Can mix and match as you please.
- Lineal descendent of the original Lisp.
- C Interop (FFI)
- Clojure(Script):
- Opinionated. Emphasis on functional programming and concurrency.
- Concurrency "channels" heavily inspired by golang.
- Mutating of bindings (references) is strongly discouraged.
- Provides full interop with host platforms/ecosystems (JVM/JS/CLR).
- Support for lazy sequences - compute/evaluate only the chunks of a collection that you actually need. Potential for data structures of infinite size.
- Thread-safe semantics for mutable values, including an implementation of Software Transactional Memory - perform ACID (not durable because it's in memory), database-like transactions on variable values. An alternative to explicit lock-based synchronization.
- ClojureScript targets Google's Closure Compiler for compiling to JS, including whole program optimization. This can result in much smaller JS file delivery.
- Racket:
- Promotes itself as a "programming-language programming language", provides facilities for defining other languages (general purpose or domain specific) through Racket, and then writing programs in those languages to be compiled by Racket
**Build systems, repos, notable libraries and other operational tooling:**
- Common Lisp:
- Quicklisp (package manager)
- Clack (webserver)
- Bordeau threads
- Clojure(Script):
- Leiningen: https://leiningen.org/
New to clojure? Stick to this for now.
'lein uberjar' will kick out a JAR file. Devops already knows how to deal with these.
- Boot: https://github.com/boot-clj/boot
Build system on steroids.
For when you want total control over your build process
- For web development, make sure to look at the Ring, Compojure and Hiccup libraries.
- Categorized library directory: https://www.clojure-toolbox.com/
- Libary repository: https://clojars.org/
- For browser-based development in ClojureScript with real hot-loading: https://github.com/bhauman/lein-figwheel
- Racket:
- Racket ships with raco, a build tool that creates modules, standalone executables, documentation, etc
**What platforms can Lisps run on?**
- Common Lisp: Various implementations, interpreted, compiles to native.
- Clojure(Script): JVM/JS/CLR.
- Racket: Runs on Windows, MacOS, and Linux, by building native binaries
**Learning resources, blogs, sources of information:**
- Common Lisp:
- Practical Common Lisp (book available online): http://www.gigamonkeys.com/book/
- Land of Lisp: http://landoflisp.com/
- Common Lisp Hyperspec: http://clhs.lisp.se/
- Lisp koans: https://github.com/google/lisp-koans
- Planet Lisp (blog aggregation): http://planet.lisp.org/
- Common Lisp Wiki: https://cliki.net/
- Simplified common lisp reference: http://jtra.cz/stuff/lisp/sclr/index.html
- Learning Lisp fast: https://cs.gmu.edu/~sean/lisp/LispTutorial.html
- Articulate common lisp (a website that tries to cover beginner topics with fewer hard opinions): http://articulate-lisp.com/
- State of the common lisp ecosystem, 2015: http://borretti.me/article/common-lisp-sotu-2015
- Lisp subreddit: https://www.reddit.com/r/lisp/
- Wikipedia article on CAR and CDR (a central concept in lisp lists): https://en.wikipedia.org/wiki/CAR_and_CDR
- http://random-state.net/files/nikodemus-cl-faq.html
- Clojure(Script):
- "Clojure for the Brave and True", a book somewhat akin to 'Automate the boring stuff', but aimed at Clojure: https://www.braveclojure.com/
- Clojure Homepage: https://clojure.org/api/cheatsheet
- Clojure GitHub: https://clojure.github.io/clojure/
- Katas: https://github.com/marshallshen/clojure-katas
- Koans: https://github.com/functional-koans/clojure-koans
- 4Clojure - a set of 150+ problems for practicing clojure, with interpretting and tests on the page: https://www.4clojure.com/
- Clojure subreddit: https://www.reddit.com/r/Clojure/
- Stand up a simple web app in Clojure: http://clojure-doc.org/articles/tutorials/basic_web_development.html
- An article explaining the basics of laziness available in Clojure: http://clojure-doc.org/articles/language/laziness.html
- Scheme:
- Probably the de facto guide to Scheme is known as SICP - "Structure and Interpretation of Computer Programs". This is a book written by a couple of MIT professors, which was used as a textbook for introductory programming courses. It uses Scheme to teach principals of programming. It should probably be noted that this book and these courses are not focused on teaching Scheme (they cover the majority of the Scheme language in the first lecture/chapter) - they're focused on teaching computer programming concepts, and Scheme is just the language used to express those concepts.
- The SICP book online (freely available): https://mitpress.mit.edu/sites/default/files/sicp/index.html
- 2004 MIT SICP course playlist (higher quality, standalone video): https://www.youtube.com/playlist?list=PL7BcsI5ueSNFPCEisbaoQ0kXIDX9rR5FF
- The 2010 UC Berkeley SICP course (recorded in classroom, somewhat lower fidelity): https://www.youtube.com/playlist?list=PLhMnuBfGeCDNgVzLPxF9o5UNKG1b-LFY9
- Racket:
- The jumping-off point for Racket info (documentation, tools, getting started, etc) is https://racket-lang.org/.
- IDEs/editors:
- Lisps in general: Emacs - Emacs has been called "a great operating system, lacking only a decent editor". The Emacs community has a lot of lispers, partially because Emacs plugin are written mostly in ELisp - a dialect of Lisp that is at the core of Emacs' extendability. As such, many Lisps have Emacs packages for editing, running, debugging, project maintenance, etc, and Emacs has packages for version control, file/directory management, and even things like personal organization (basically all done in text buffers).
- Common Lisp: Emacs with SLIME, Vim with SLIMV, Portacle (kinda), LispWorks, Allegro CL.
- Clojure: Nightcode, Light Table, IntelliJ Cursive, Eclipse with counterclockwise, Emacs with CIDER, VIM with Fireplace.
- Racket: By default, Racket comes with DrRacket, an IDE with extensive documentation of the language
**Other resources:**
- A couple of talks given by Rich Hickey, creator of Clojure
- Simple Made Easy - an examination of the definitions of simple, easy, and complex, and some of the powers of simplicity: https://www.infoq.com/presentations/Simple-Made-Easy
- Clojure, Made Simple - a talk about shortcomings and incidental complexity associated with OO programming, and Clojure's responses to them: https://www.youtube.com/watch?v=VSdnJDO-xdg
**Code examples:**
- Hello World
Common Lisp:
```
(print "Hello, World!")
```
Scheme:
```
(print "Hello, World!")
```
Clojure (as a JVM program entry point):
```
(defn -main
"A documentation string for my hello world function"
[& args]
(println "Hello, World!"))
```
Racket:
```lisp
#lang racket
(println "Hello, World!")
```
ALGOL60, as implemented in Racket (to demonstrate the flexibility offered by Racket):
```
#lang algol60
begin
printsln(`Hello, World!')
end
```
- Take two numbers as input, add them, and format an output string
Common Lisp:
```
(let ((first (block a (write-line "first number:") (read)))
(second (block b (write-line "second number: ") (read))))
(format t "The sum of ~A and ~A is ~D" first second (+ first second)))
```
Scheme:
```
(let ((first (begin (display "first number:") (read)))
(second (begin (display "second number: ") (read))))
(format #t "The sum of ~s and ~s is ~s" first second (+ first second)))
```
Clojure:
```
(let [first (do (println "first number: ") (Integer/parseInt (read-line)))
second (do (println "second number: ") (Integer/parseInt (read-line)))]
(printf "The sum of %d and %d is %d" first second (+ first second)))
```
Racket:
```lisp
#lang racket
(let ((first (begin (print "first number:")(read)))
(second (begin (print "second number:") (read))))
(printf "The sum of ~s and ~s is ~s" first second (+ first second)))
```
- A very basic macro in Clojure
```
;; definition - we'll take an expression, evaluate it once, print the formatted string, and then return the result
(defmacro log-call [form]
`(let [outcome# ~form]
(do
(println "The evaluation of '" '~form "' resulted in:" outcome#)
outcome#)))
;; usage
(log-call (reduce + (range 10)))
;; prints this: The evaluation of ' (reduce + (range 10)) ' resulted in: 45
;; and returns 45
```
- A really simple Clojure web site using the ring and compojure libraries
```
;; define a namespace for our functions, and import routing and default request handling functions
(ns hello-web.handler
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
;; define the route for the root page
(defroutes app-routes
(GET "/" [] "Hello, World!")
(route/not-found " Not Found "))
;; and this is our "ring handler" function that returns a handler (our routes) wrapped in some vaguely secure defaults
(def app
(wrap-defaults app-routes site-defaults))
```
- Memoizing pure functions in Clojure
```
(defn expensive
[number]
(Thread/sleep 1000)
(inc number))
(defn memoization-demo
"Memoization keeps track of what the args to a function were. Caches the results."
[]
(let [memo-expensive (memoize expensive)]
(println "Starting memoization tests. First run:")
(dotimes [i 5]
;; these calls take one second each
(time (println "Uncached function call" (memo-expensive i))))
(println "Memoization test, second run:")
(dotimes [i 5]
;; these calls take a fraction of a millisecond
(time (println "Cached function call" (memo-expensive i))))
(println "Memoization caches the output of functions, so that expensive pure functions can be computed once.")))
```
- Lazy sequences in Clojure
```
(defn fib-seq
"Returns a lazy sequence of Fibonacci numbers. Copied from http://clojure-doc.org/articles/language/laziness.html"
([]
(fib-seq 0 1))
([a b]
(lazy-seq
(cons b (fib-seq b (+ a b))))))
(defn lazy-fib-seq-demo
[]
(println "The first 20 fibonacci numbers, obtained from a lazy sequence:" (take 20 (fib-seq))))
```
- Collatz sequence in Scheme
```
(define (collatz n)
(cond
[(equal? n 1)(format #t "1")]
[(even? n) (begin (format #t "~s -> " n)(collatz (/ n 2)))]
[else (begin (format #t "~s -> " n) (collatz (+ 1 (* 3 n))))]))
```
- FizzBuzz from 1 to n using lazy evaluation in Racket
```lisp
#lang lazy
(define fizzes (cycle "" "" "Fizz"))
(define buzzes (cycle "" "" "" "" "Buzz"))
(define words (map string-append fizzes buzzes))
(define (fizzbuzz n)
(!! (take n
(map (lambda (word number) (if (string=? "" word) number word))
words (build-list n (λ (x)(+ x 1)))))))
```