forked from orion/obsidian
init
This commit is contained in:
commit
ebb7d92134
21
fp/.obsidian/app.json
vendored
Normal file
21
fp/.obsidian/app.json
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"mobileToolbarCommands": [
|
||||||
|
"command-palette:open",
|
||||||
|
"editor:insert-codeblock",
|
||||||
|
"editor:insert-wikilink",
|
||||||
|
"editor:insert-embed",
|
||||||
|
"editor:insert-tag",
|
||||||
|
"editor:attach-file",
|
||||||
|
"editor:toggle-bullet-list",
|
||||||
|
"editor:toggle-numbered-list",
|
||||||
|
"editor:toggle-checklist-status",
|
||||||
|
"editor:indent-list",
|
||||||
|
"editor:unindent-list",
|
||||||
|
"editor:undo",
|
||||||
|
"editor:redo",
|
||||||
|
"editor:configure-toolbar"
|
||||||
|
],
|
||||||
|
"livePreview": false,
|
||||||
|
"promptDelete": false,
|
||||||
|
"alwaysUpdateLinks": true
|
||||||
|
}
|
6
fp/.obsidian/appearance.json
vendored
Normal file
6
fp/.obsidian/appearance.json
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"theme": "obsidian",
|
||||||
|
"accentColor": "#745eff",
|
||||||
|
"interfaceFontFamily": "",
|
||||||
|
"baseFontSize": 18
|
||||||
|
}
|
3
fp/.obsidian/community-plugins.json
vendored
Normal file
3
fp/.obsidian/community-plugins.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"templater-obsidian"
|
||||||
|
]
|
30
fp/.obsidian/core-plugins-migration.json
vendored
Normal file
30
fp/.obsidian/core-plugins-migration.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"file-explorer": true,
|
||||||
|
"global-search": true,
|
||||||
|
"switcher": true,
|
||||||
|
"graph": true,
|
||||||
|
"backlink": true,
|
||||||
|
"canvas": true,
|
||||||
|
"outgoing-link": true,
|
||||||
|
"tag-pane": true,
|
||||||
|
"properties": false,
|
||||||
|
"page-preview": true,
|
||||||
|
"daily-notes": true,
|
||||||
|
"templates": true,
|
||||||
|
"note-composer": true,
|
||||||
|
"command-palette": true,
|
||||||
|
"slash-command": false,
|
||||||
|
"editor-status": true,
|
||||||
|
"bookmarks": true,
|
||||||
|
"markdown-importer": false,
|
||||||
|
"zk-prefixer": false,
|
||||||
|
"random-note": false,
|
||||||
|
"outline": true,
|
||||||
|
"word-count": true,
|
||||||
|
"slides": false,
|
||||||
|
"audio-recorder": false,
|
||||||
|
"workspaces": false,
|
||||||
|
"file-recovery": true,
|
||||||
|
"publish": false,
|
||||||
|
"sync": false
|
||||||
|
}
|
20
fp/.obsidian/core-plugins.json
vendored
Normal file
20
fp/.obsidian/core-plugins.json
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
"file-explorer",
|
||||||
|
"global-search",
|
||||||
|
"switcher",
|
||||||
|
"graph",
|
||||||
|
"backlink",
|
||||||
|
"canvas",
|
||||||
|
"outgoing-link",
|
||||||
|
"tag-pane",
|
||||||
|
"page-preview",
|
||||||
|
"daily-notes",
|
||||||
|
"templates",
|
||||||
|
"note-composer",
|
||||||
|
"command-palette",
|
||||||
|
"editor-status",
|
||||||
|
"bookmarks",
|
||||||
|
"outline",
|
||||||
|
"word-count",
|
||||||
|
"file-recovery"
|
||||||
|
]
|
22
fp/.obsidian/graph.json
vendored
Normal file
22
fp/.obsidian/graph.json
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"collapse-filter": true,
|
||||||
|
"search": "",
|
||||||
|
"showTags": false,
|
||||||
|
"showAttachments": false,
|
||||||
|
"hideUnresolved": false,
|
||||||
|
"showOrphans": true,
|
||||||
|
"collapse-color-groups": true,
|
||||||
|
"colorGroups": [],
|
||||||
|
"collapse-display": true,
|
||||||
|
"showArrow": false,
|
||||||
|
"textFadeMultiplier": 0,
|
||||||
|
"nodeSizeMultiplier": 1,
|
||||||
|
"lineSizeMultiplier": 1,
|
||||||
|
"collapse-forces": true,
|
||||||
|
"centerStrength": 0.518713248970312,
|
||||||
|
"repelStrength": 10,
|
||||||
|
"linkStrength": 1,
|
||||||
|
"linkDistance": 250,
|
||||||
|
"scale": 1.9042482571987516,
|
||||||
|
"close": false
|
||||||
|
}
|
30
fp/.obsidian/plugins/templater-obsidian/data.json
vendored
Normal file
30
fp/.obsidian/plugins/templater-obsidian/data.json
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"command_timeout": 5,
|
||||||
|
"templates_folder": "Templates",
|
||||||
|
"templates_pairs": [
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"trigger_on_file_creation": false,
|
||||||
|
"auto_jump_to_cursor": false,
|
||||||
|
"enable_system_commands": true,
|
||||||
|
"shell_path": "",
|
||||||
|
"user_scripts_folder": "Scripts",
|
||||||
|
"enable_folder_templates": true,
|
||||||
|
"folder_templates": [
|
||||||
|
{
|
||||||
|
"folder": "",
|
||||||
|
"template": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"syntax_highlighting": true,
|
||||||
|
"syntax_highlighting_mobile": false,
|
||||||
|
"enabled_templates_hotkeys": [
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"startup_templates": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
19
fp/.obsidian/plugins/templater-obsidian/main.js
vendored
Normal file
19
fp/.obsidian/plugins/templater-obsidian/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
11
fp/.obsidian/plugins/templater-obsidian/manifest.json
vendored
Normal file
11
fp/.obsidian/plugins/templater-obsidian/manifest.json
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"id": "templater-obsidian",
|
||||||
|
"name": "Templater",
|
||||||
|
"version": "2.7.1",
|
||||||
|
"description": "Create and use templates",
|
||||||
|
"minAppVersion": "1.5.0",
|
||||||
|
"author": "SilentVoid",
|
||||||
|
"authorUrl": "https://github.com/SilentVoid13",
|
||||||
|
"helpUrl": "https://silentvoid13.github.io/Templater/",
|
||||||
|
"isDesktopOnly": false
|
||||||
|
}
|
220
fp/.obsidian/plugins/templater-obsidian/styles.css
vendored
Normal file
220
fp/.obsidian/plugins/templater-obsidian/styles.css
vendored
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
.templater_search {
|
||||||
|
width: calc(100% - 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_div {
|
||||||
|
border-top: 1px solid var(--background-modifier-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_div > .setting-item {
|
||||||
|
border-top: none !important;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_div > .setting-item > .setting-item-control {
|
||||||
|
justify-content: space-around;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_div
|
||||||
|
> .setting-item
|
||||||
|
> .setting-item-control
|
||||||
|
> .setting-editor-extra-setting-button {
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_donating {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_title {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_template {
|
||||||
|
align-self: center;
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_cmd {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater_div2 > .setting-item {
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater-prompt-div {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater-prompt-form {
|
||||||
|
display: flex;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater-prompt-input {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.templater-button-div {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.templater-prompt-input {
|
||||||
|
height: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.templater-prompt-input:focus {
|
||||||
|
border-color: var(--interactive-accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .templater-command-bg {
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
background-color: var(--background-primary-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command {
|
||||||
|
font-size: 0.85em;
|
||||||
|
font-family: var(--font-monospace);
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .templater-inline .cm-templater-command {
|
||||||
|
background-color: var(--background-primary-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-templater-opening-tag {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-templater-closing-tag {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-templater-interpolation-tag {
|
||||||
|
color: var(--code-property, #008bff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-templater-execution-tag {
|
||||||
|
color: var(--code-function, #c0d700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-keyword {
|
||||||
|
color: var(--code-keyword, #00a7aa);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-atom {
|
||||||
|
color: var(--code-normal, #f39b35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-value,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-number,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-type {
|
||||||
|
color: var(--code-value, #a06fca);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-def,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-type.cm-def {
|
||||||
|
color: var(--code-normal, var(--text-normal));
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-property,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-property.cm-def,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-attribute {
|
||||||
|
color: var(--code-function, #98e342);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-variable,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-variable-2,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-variable-3,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-meta {
|
||||||
|
color: var(--code-property, #d4d4d4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-callee,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-operator,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-qualifier,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-builtin {
|
||||||
|
color: var(--code-operator, #fc4384);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-tag {
|
||||||
|
color: var(--code-tag, #fc4384);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-comment,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-comment.cm-tag,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-comment.cm-attribute {
|
||||||
|
color: var(--code-comment, #696d70);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-string,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-string-2 {
|
||||||
|
color: var(--code-string, #e6db74);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-header,
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-hr {
|
||||||
|
color: var(--code-keyword, #da7dae);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-link {
|
||||||
|
color: var(--code-normal, #696d70);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cm-s-obsidian .cm-templater-command.cm-error {
|
||||||
|
border-bottom: 1px solid #c42412;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-hints {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10;
|
||||||
|
overflow: hidden;
|
||||||
|
list-style: none;
|
||||||
|
|
||||||
|
margin: 0;
|
||||||
|
padding: 2px;
|
||||||
|
|
||||||
|
-webkit-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
-moz-box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
box-shadow: 2px 3px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid silver;
|
||||||
|
|
||||||
|
background: white;
|
||||||
|
font-size: 90%;
|
||||||
|
font-family: monospace;
|
||||||
|
|
||||||
|
max-height: 20em;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-hint {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
white-space: pre;
|
||||||
|
color: black;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.CodeMirror-hint-active {
|
||||||
|
background: #08f;
|
||||||
|
color: white;
|
||||||
|
}
|
164
fp/.obsidian/workspace-mobile.json
vendored
Normal file
164
fp/.obsidian/workspace-mobile.json
vendored
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
{
|
||||||
|
"main": {
|
||||||
|
"id": "bccae7928f1a9905",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "217d72f4193a5b9c",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "8992473db8c2f73c",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "Language/Infix Operators.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "vertical"
|
||||||
|
},
|
||||||
|
"left": {
|
||||||
|
"id": "b1878108e328d939",
|
||||||
|
"type": "mobile-drawer",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "33a47f685e8878d0",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "file-explorer",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "657f40de10459a91",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "search",
|
||||||
|
"state": {
|
||||||
|
"query": "",
|
||||||
|
"matchingCase": false,
|
||||||
|
"explainSearch": false,
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "e7a04a503b0bf0f1",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "tag",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"useHierarchy": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "772471bd9f5963aa",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "bookmarks",
|
||||||
|
"state": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"currentTab": 0
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"id": "c869efdcbafae729",
|
||||||
|
"type": "mobile-drawer",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "6899289773dd5346",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "backlink",
|
||||||
|
"state": {
|
||||||
|
"file": "Language/Infix Operators.md",
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": "",
|
||||||
|
"backlinkCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "534b6ce9b4f07b6a",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outgoing-link",
|
||||||
|
"state": {
|
||||||
|
"file": "Language/Infix Operators.md",
|
||||||
|
"linksCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ff96767c96b7f595",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outline",
|
||||||
|
"state": {
|
||||||
|
"file": "Language/Infix Operators.md"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"currentTab": 0
|
||||||
|
},
|
||||||
|
"left-ribbon": {
|
||||||
|
"hiddenItems": {
|
||||||
|
"switcher:Open quick switcher": false,
|
||||||
|
"graph:Open graph view": false,
|
||||||
|
"canvas:Create new canvas": false,
|
||||||
|
"daily-notes:Open today's daily note": false,
|
||||||
|
"templates:Insert template": false,
|
||||||
|
"command-palette:Open command palette": false,
|
||||||
|
"templater-obsidian:Templater": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": "8992473db8c2f73c",
|
||||||
|
"lastOpenFiles": [
|
||||||
|
"Language/Infix Operators.md",
|
||||||
|
"Language/Functions.md",
|
||||||
|
"Language/Data Structures.md",
|
||||||
|
"Class/Functor.md",
|
||||||
|
"Monad/Effect",
|
||||||
|
"Monad/Aff",
|
||||||
|
"Language/Typeclasses.md",
|
||||||
|
"Language/Modules.md",
|
||||||
|
"Monad/Aff.md",
|
||||||
|
"Monad/Effect.md",
|
||||||
|
"Untitled",
|
||||||
|
"Monad",
|
||||||
|
"Data.md",
|
||||||
|
"Language",
|
||||||
|
"Data/Int.md",
|
||||||
|
"Class/Apply.md",
|
||||||
|
"Data/Array.md",
|
||||||
|
"Class",
|
||||||
|
"Data",
|
||||||
|
"Data/Maybe.md",
|
||||||
|
"Templates/Pursuit Link.md",
|
||||||
|
"Untitled.md",
|
||||||
|
"Templates",
|
||||||
|
"Templates",
|
||||||
|
"Untitled 1.md",
|
||||||
|
"Scripts/pursuit_link.js"
|
||||||
|
]
|
||||||
|
}
|
0
fp/.trash/Data.md
Normal file
0
fp/.trash/Data.md
Normal file
0
fp/.trash/Untitled 1.md
Normal file
0
fp/.trash/Untitled 1.md
Normal file
1
fp/.trash/Untitled.md
Normal file
1
fp/.trash/Untitled.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Effect.untilE](https://pursuit.purescript.org/packages/purescript-effec
|
12
fp/Class/Apply.md
Normal file
12
fp/Class/Apply.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
Generalizes [[Functor]] to functions with 2+ arguments
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
apply ::
|
||||||
|
forall f a b
|
||||||
|
. Apply f
|
||||||
|
=> f (a -> b)
|
||||||
|
-> f a
|
||||||
|
-> f b
|
||||||
|
|
||||||
|
infixl apply as <*>
|
||||||
|
```
|
57
fp/Class/Functor.md
Normal file
57
fp/Class/Functor.md
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
## What
|
||||||
|
[[Typeclasses|Typeclass]] defining the [[Functions|function]] `map`, [[Infix Operators|operators]] `<$>`, and `<#>`.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
class Functor f where
|
||||||
|
map :: forall a b. (a -> b) -> f a -> f b
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why
|
||||||
|
Modify the data contained in a [[Data Structures|data structure]]
|
||||||
|
|
||||||
|
### Abstracts
|
||||||
|
- For every element in [[Collections|collection]] ...
|
||||||
|
- When [[Maybe|nullable]] value is non-null ...
|
||||||
|
- When _(potentially async)_ [[Effect|IO]] resolves ...
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
### [[Array]] of [[Int]]
|
||||||
|
```haskell
|
||||||
|
add 1 <$> [1, 2, 3]
|
||||||
|
-- [2, 3, 4]
|
||||||
|
```
|
||||||
|
|
||||||
|
### [[Maybe]] of [[Int]]
|
||||||
|
```haskell
|
||||||
|
add 1 <$> Just 1
|
||||||
|
-- Just
|
||||||
|
|
||||||
|
add 1 <$> Nothing
|
||||||
|
-- Nothing
|
||||||
|
```
|
||||||
|
|
||||||
|
### [[Effect]] of [[Int]]
|
||||||
|
See also:
|
||||||
|
- [[Bind]]
|
||||||
|
- [[Show]]
|
||||||
|
- [[compose]]
|
||||||
|
- [[do notation]]
|
||||||
|
```haskell
|
||||||
|
import Node.FS.Sync (readTextFile, writeTextFile)
|
||||||
|
import Node.Encoding (Encoding(..))
|
||||||
|
import Data.Int as Int
|
||||||
|
|
||||||
|
writeNum :: Int -> Effect Unit
|
||||||
|
writeNum n = writeTextFile "num.txt" (show n) UTF8
|
||||||
|
|
||||||
|
readNum :: Effect Int
|
||||||
|
readNum =
|
||||||
|
readTextFile "num.txt" UTF8
|
||||||
|
>>= (Int.fromString >>> liftMaybe (error "invalid integer"))
|
||||||
|
|
||||||
|
main = do
|
||||||
|
writeNum
|
||||||
|
n <- add 1 <$> readNum
|
||||||
|
log $ show n
|
||||||
|
-- 2
|
||||||
|
```
|
2
fp/Data/Array.md
Normal file
2
fp/Data/Array.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# What
|
||||||
|
# Why
|
5
fp/Data/Int.md
Normal file
5
fp/Data/Int.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# What
|
||||||
|
Signed integers
|
||||||
|
|
||||||
|
# Why
|
||||||
|
You want numbers without decimals
|
2
fp/Data/Maybe.md
Normal file
2
fp/Data/Maybe.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# What
|
||||||
|
# Why
|
2
fp/Language/Data Structures.md
Normal file
2
fp/Language/Data Structures.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# What
|
||||||
|
# Why
|
204
fp/Language/Functions.md
Normal file
204
fp/Language/Functions.md
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
## Applying
|
||||||
|
Functions are applied by placing expressions after the function name, separated by whitespace, e.g.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Math.pow(2, 10)
|
||||||
|
```
|
||||||
|
equivalent would be
|
||||||
|
```haskell
|
||||||
|
Number.pow 2.0 10.0
|
||||||
|
```
|
||||||
|
|
||||||
|
## Defining
|
||||||
|
Parts of a function definition are:
|
||||||
|
- type signature (optional)
|
||||||
|
- 1 or more "implementations" of the type signature
|
||||||
|
- name
|
||||||
|
- 0 or more arguments
|
||||||
|
- function body
|
||||||
|
|
||||||
|
### Type Signature
|
||||||
|
Function type signatures follow the form `<name> :: <type>`, and are always the line immediately above the function implementations, e.g.
|
||||||
|
|
||||||
|
this `add` has 2 `Int` arguments and returns an `Int`.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
add2 :: Int -> Int -> Int
|
||||||
|
-- ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Name
|
||||||
|
function names can contain any alphanumeric character, `_`, `'` but the first character must be a lowercase alpha or `_`.
|
||||||
|
|
||||||
|
### Arguments
|
||||||
|
Arguments are space-separated, e.g.
|
||||||
|
|
||||||
|
the first [[Int]] argument is bound to `a`, the second to `b`.
|
||||||
|
```haskell
|
||||||
|
add :: Int -> Int -> Int
|
||||||
|
add a b = -- ...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Body
|
||||||
|
The expression returned by the function, e.g.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
add a b = a + b
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multiple Implementations
|
||||||
|
Functions may have multiple implementations that change behavior based on the shape of the arguments.
|
||||||
|
|
||||||
|
This is _similar_ to method overloading in OOP languages, but differs in that the number of arguments and type of the arguments must be the same for all implementations.
|
||||||
|
|
||||||
|
Functions can have any number of implementations, as long as all possible inputs are covered exhaustively.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
this implementation of [[Number]] division has 2 paths:
|
||||||
|
- when the denominator is zero, yields `Infinity`
|
||||||
|
- otherwise, performs the division
|
||||||
|
```haskell
|
||||||
|
div num 0.0 = infinity
|
||||||
|
div num den = num / den
|
||||||
|
```
|
||||||
|
|
||||||
|
this is equivalent to
|
||||||
|
```haskell
|
||||||
|
div num den =
|
||||||
|
if den == 0.0 then
|
||||||
|
infinity
|
||||||
|
else
|
||||||
|
num / den
|
||||||
|
```
|
||||||
|
|
||||||
|
### Guards
|
||||||
|
Single function implementations may have guards, which allows for conditional checks on inputs (as opposed to structural pattern matching)
|
||||||
|
|
||||||
|
This pattern often takes up less space than explicit [[if then else Expressions]]
|
||||||
|
|
||||||
|
Guard patterns are placed after the function arguments and take the form `| <Boolean expr> = <body>`. There can be any number of guard patterns, as long as all cases are exhaustively covered.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
Strings can't be structurally pattern matched, so in order to ask if a string starts with a substring we need to call a function like `Data.String.Utils.startsWith`.
|
||||||
|
|
||||||
|
We could do this with `if then else`:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
ensureLeadingSlash :: String -> String
|
||||||
|
ensureLeadingSlash str =
|
||||||
|
if String.Util.startsWith "/" then
|
||||||
|
str
|
||||||
|
else
|
||||||
|
"/" <> str
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, we could implement this with guard patterns:
|
||||||
|
```haskell
|
||||||
|
ensureLeadingSlash :: String -> String
|
||||||
|
ensureLeadingSlash str
|
||||||
|
| String.Util.startsWith "/" str = str
|
||||||
|
| otherwise = "/" <> str
|
||||||
|
```
|
||||||
|
|
||||||
|
When the first pattern `String.Util.startsWith "/" str` returns `true`, the function will use `... = str`. Otherwise, it will prepend `/` to `str`.
|
||||||
|
|
||||||
|
> [!info]
|
||||||
|
> `otherwise` is simply an alias for `true`, specifically for better-reading fallthrough guard patterns.
|
||||||
|
|
||||||
|
## Currying
|
||||||
|
Functions are curried in PureScript, meaning that "a function of 2 arguments" is actually "a function of 1 argument, returning a function of 1 argument."
|
||||||
|
|
||||||
|
This allows you to call many functions point-free, and think in terms of "building up to a conclusion" rather than "i need everything at once."
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
add :: Int -> Int -> Int
|
||||||
|
-- ...
|
||||||
|
|
||||||
|
add2 :: Int -> Int
|
||||||
|
add2 n = add 2 n
|
||||||
|
```
|
||||||
|
|
||||||
|
is equivalent to
|
||||||
|
```haskell
|
||||||
|
add :: Int -> Int -> Int
|
||||||
|
-- ...
|
||||||
|
|
||||||
|
add2 :: Int -> Int
|
||||||
|
add2 = add 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Walking through this:
|
||||||
|
|
||||||
|
`add` has type `Int -> Int -> Int`
|
||||||
|
|
||||||
|
if we give `add` a single `Int` argument, it will return a function of type `Int -> Int`. This function is the "second half" of `add`, waiting for it's second argument. Since `Int -> Int` is the type of `add2`, we can simply say `add2 = add 2`.
|
||||||
|
|
||||||
|
> [!info]
|
||||||
|
> as a rule, any time a function's last argument is passed as the last argument to another function, you can remove both.
|
||||||
|
> ```haskell
|
||||||
|
> f a = g b c a
|
||||||
|
>
|
||||||
|
> \a -> g b c a
|
||||||
|
>
|
||||||
|
> f a = g $ h a
|
||||||
|
> ```
|
||||||
|
> can be written as
|
||||||
|
> ```haskell
|
||||||
|
> f = g b c
|
||||||
|
>
|
||||||
|
> g b c
|
||||||
|
>
|
||||||
|
> f = g <<< h
|
||||||
|
> ```
|
||||||
|
|
||||||
|
## Working with Functions
|
||||||
|
Functions being first-class citizens means that it's important that applying, extending and combining functions must be easy.
|
||||||
|
|
||||||
|
|
||||||
|
### Composition
|
||||||
|
The most common pattern by far; piping the output of a function into the input of the next.
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
compose :: forall a b c. (b -> c) -> (a -> b) -> (a -> c)
|
||||||
|
compose g f a = g (f a)
|
||||||
|
```
|
||||||
|
|
||||||
|
`compose` (infix as `<<<`) accepts 2 functions; `f` which is `a -> b` and `g`; `b -> c`. `compose` returns a new function `a -> c` that "glues" the 2 functions together; piping the output of `f` into `g`.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
consider a function `normalizedPathSegments :: String -> Array String`
|
||||||
|
|
||||||
|
This function would normalize a file path, removing trailing / leading slashes and resolving relative paths, then split the path by its segments.
|
||||||
|
|
||||||
|
A very good approach would be to split this function into separate single-purpose components, e.g.
|
||||||
|
|
||||||
|
- `stripLeadingSlash :: String -> String`
|
||||||
|
- `stripTrailingSlash :: String -> String`
|
||||||
|
- `splitPath :: String -> Array String`
|
||||||
|
- `normalizePathSegments :: Array String -> Array String`
|
||||||
|
|
||||||
|
then define `normalizedPathSegments` like so:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
normalizedPathSegments :: String -> Array String
|
||||||
|
normalizedPathSegments =
|
||||||
|
normalizePathSegments
|
||||||
|
<<< splitPath
|
||||||
|
<<< stripTrailingSlash
|
||||||
|
<<< stripLeadingSlash
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
map map map
|
||||||
|
(a -> b) -> (f a) -> (f b)
|
||||||
|
(a -> b) -> (c -> a) -> (c -> b)
|
||||||
|
|
||||||
|
((a -> b) -> (c -> a) -> (c -> b))
|
||||||
|
-> ((c -> b) -> (a -> b))
|
||||||
|
-> ((c -> b) -> (c -> a))
|
||||||
|
|
107
fp/Language/Infix Operators.md
Normal file
107
fp/Language/Infix Operators.md
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
Infix operators are symbols that alias binary (2-argument) [[Functions|functions]].
|
||||||
|
|
||||||
|
They're defined like so:
|
||||||
|
```haskell
|
||||||
|
infixl <precedence> <fn> as <operator>
|
||||||
|
-- or
|
||||||
|
infixr -- ..
|
||||||
|
```
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
```haskell
|
||||||
|
eq :: Int -> Int -> Boolean
|
||||||
|
eq = -- ...
|
||||||
|
|
||||||
|
add :: Int -> Int -> Int
|
||||||
|
add = -- ...
|
||||||
|
|
||||||
|
infixl 1 add as +
|
||||||
|
infixl 1 eq as ==
|
||||||
|
|
||||||
|
(1 + 2) == 3
|
||||||
|
-- same as
|
||||||
|
eq (add 1 2) 3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Associativity
|
||||||
|
Operators are either left or right associative (`infixl` or `infixr`).
|
||||||
|
|
||||||
|
When multiple infix operators with the same precedence are chained, associativity tells the language how to group them, e.g. `&&` is right-associative, while `*` is left associative.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
```haskell
|
||||||
|
|
||||||
|
a && b && c
|
||||||
|
-- interpreted as
|
||||||
|
(a && (b && c))
|
||||||
|
|
||||||
|
a * b * c
|
||||||
|
-- interpreted as
|
||||||
|
((a * b) * c)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Precedence
|
||||||
|
The precedence of operators is an int from 1-9 used as a tie-break, for example in
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
a + b == c
|
||||||
|
```
|
||||||
|
|
||||||
|
this behaves how you'd expect; this is equivalent to
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
((a + b) == c)
|
||||||
|
```
|
||||||
|
|
||||||
|
as the precedence of `+` (6) is higher than `==`'s (4), the grouping is first done around `a + b`.
|
||||||
|
|
||||||
|
## Common Operators
|
||||||
|
|Operator|Associativity|Precedence|Aliases|
|
||||||
|
|--|--|--|--|
|
||||||
|
|`$`||||
|
||||||
|
|
||||||
|
## Directionality
|
||||||
|
Most commonly used operators have flipped variants, e.g.
|
||||||
|
- function composition has `g <<< f` or `f >>> g`
|
||||||
|
- function application has `f $ a` or `a # f`
|
||||||
|
- [[Functor|map]] has `f <$> a` or `a <#> f`
|
||||||
|
- [[Bind|bind]] has `f =<< m` or `m >>= f`
|
||||||
|
|
||||||
|
In general, right-to-left operators tend to be easier to refactor into & out of because they closely mirror the expressions they replace:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
map (add 1) maybeNum
|
||||||
|
-- into
|
||||||
|
add 1 <$> maybeNum
|
||||||
|
|
||||||
|
foo (bar a)
|
||||||
|
-- into
|
||||||
|
foo <<< bar
|
||||||
|
```
|
||||||
|
|
||||||
|
Left-to-right, on the other hand, can read better to humans and plays better with pipelines containing both [[Bind|bind `>>=`]] and [[Functor|map `<#>`]].
|
||||||
|
|
||||||
|
Consider an expression piping `Maybe String` to `split :: String -> Array String` then `Data.Array.NonEmpty.fromArray :: Array a -> Maybe (NonEmptyArray a)`, then `toLower` each element:
|
||||||
|
|
||||||
|
```haskell
|
||||||
|
String.toLower
|
||||||
|
<$> (
|
||||||
|
Array.NonEmpty.fromArray
|
||||||
|
=<< String.split "."
|
||||||
|
<$> mStr
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
We need to wrap the right hand of the last `map` because the precedence of `=<<` is `1` (the lowest) and the precedence of `<$>` is `4`.
|
||||||
|
|
||||||
|
Written RTL, though, gives:
|
||||||
|
```haskell
|
||||||
|
mStr
|
||||||
|
<#> String.split "."
|
||||||
|
>>= Array.NonEmpty.fromArray
|
||||||
|
<#> String.toLower
|
||||||
|
```
|
||||||
|
|
||||||
|
This works because `<#>`'s precedence (1) is the same as `>>=`. The lower precedence on flipped map means you'll often need more parentheses wrapping its arguments `(..) <#> (..) >>= (..)` as opposed to entire expressions `.. <$> (.. =<< ..)`.
|
||||||
|
|
||||||
|
Personally, I try to stick to RTL except for expressions including bind.
|
0
fp/Language/Modules.md
Normal file
0
fp/Language/Modules.md
Normal file
2
fp/Language/Typeclasses.md
Normal file
2
fp/Language/Typeclasses.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# What
|
||||||
|
# Why
|
2
fp/Monad/Aff.md
Normal file
2
fp/Monad/Aff.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# What
|
||||||
|
# Why
|
2
fp/Monad/Effect.md
Normal file
2
fp/Monad/Effect.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# What
|
||||||
|
# Why
|
12
fp/Scripts/pursuit_link.js
Normal file
12
fp/Scripts/pursuit_link.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
module.exports = async (path) => {
|
||||||
|
path = await path
|
||||||
|
pkg = path.split('/')[0]
|
||||||
|
mod = path.split('/')[1]
|
||||||
|
let dots = path.split('.')
|
||||||
|
let mod = dots.filter(s => s[0].toUpperCase() === s[0]).join('.')
|
||||||
|
let last = dots[dots.length - 1]
|
||||||
|
let val = last[0].toLowerCase() === last[0] ? last : ''
|
||||||
|
val = val ? `#v:${val}` : ''
|
||||||
|
const url = `https://pursuit.purescript.org/packages/purescript-${pkg}/docs/${mod}${val}`
|
||||||
|
return `[${path}](${url})`
|
||||||
|
}
|
1
fp/Templates/Pursuit Link.md
Normal file
1
fp/Templates/Pursuit Link.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
<% tp.user.pursuit_link(tp.system.prompt("Path", "", true)) %>
|
Loading…
Reference in New Issue
Block a user