I use [Tcl] as my scripting language of choice, and recently someone asked me why. This article is an attempt to answer that question.
Ousterhout's dichotomy claims that there are two general categories of programming languages:
export default class Utils { | |
/** | |
* Delete items in bulk from Cloudflare KV Storage | |
* This assumes you have defined your ENV_ variables using wrangler secrets | |
* @param {namespace} The namespace binding you defined for your script | |
*/ | |
static async deleteInBulk(namespace): Promise<Boolean> { | |
const delete_endpoint = | |
"https://api.cloudflare.com/client/v4/accounts/" + | |
EN_ACC_ID + |
modules.export = { | |
..., | |
transform: { | |
".*\\.(svg)$": "<rootDir>/svg-transform.js", | |
}, | |
} |
Recently I noticed the number of the same two questions being asked again and again on different Haskell resources. The questions were “How to get a Haskell job” and “Why is it so hard to find Haskellers?” Although these two are coming from the opposite sides of the hiring process, the answer is really just one. There is a single reason, a single core problem that causes difficulties of hiring and being hired in the Haskell community, and we should clearly articulate this problem if we want to increase the Haskell adoption.
We all know that there are many people wishing to get a Haskell job. And a visible increase of Haskell jobs looks like there should be a high demand for Haskellers. The Haskell community has also grown like crazy past years. But still, why is it so difficult to hire and to be hired? Why can’t companies just hire any single person who demonstrates a deep knowledge of Haskell in blog posts, in chats, on forums, and in talks? And why do Haskell companies avoid hirin
import { OperatorFunction } from 'ix/interfaces'; | |
import { pipe } from 'ix/iterable'; | |
import { map } from 'ix/iterable/operators'; | |
/** | |
* Creates a new type which is the first element of a non-empty tuple type. | |
* | |
* @example type T = Head<[string, number, Object]>; // string | |
*/ | |
export type Head<Ts extends [any, ...any[]]> = Ts extends [infer T, ...any[]] ? T : never; |
test('left identity', async () => { | |
async function f(x: number) { | |
return 2 * x; | |
} | |
function g(x: number) { | |
return f(x).then(y => Promise.resolve(y)); | |
} | |
const x = 2; | |
expect(await f(x)).toEqual(await g(x)); | |
}) |
ci.yaml
into .github/workflows/
Let's imagine how a given category is a monad in a bicategory of spans.
Consider the set of all the objects in the category C0
and the set of all the morphisms in the category C1
(they're all muddled together in this set). We have two functions domain : C1 -> C0
and codomain : C1 -> C0
which assign to each morphism its source and target object.
This pair of functions forms a "span" of sets, which is a diagram of this shape:
C_1
╱ ╲
dom cod
╱ ╲
any
: magic, ill-behaved type that acts like a combination of never
(the proper [bottom type]) and unknown
(the proper [top type])
never
is assignable to any
, and any
is assignable to anything at all.any & AnyTypeExpression = any
, any | AnyTypeExpression = any
unknown
: proper, well-behaved [top type]
unknown
. unknown
is only assignable to itself (unknown
) and any
.unknown & AnyTypeExpression = AnyTypeExpression
, unknown | AnyTypeExpression = unknown
any
whenever possible. Anywhere in well-typed code you're tempted to use any
, you probably want unknown
.