This commit is contained in:
Orion Kindel 2024-09-23 18:56:55 -05:00
parent ebb7d92134
commit 3701b1e2f8
Signed by untrusted user who does not match committer: orion
GPG Key ID: 6D4165AE4C928719
99 changed files with 14174 additions and 330 deletions

View File

@ -17,5 +17,8 @@
], ],
"livePreview": false, "livePreview": false,
"promptDelete": false, "promptDelete": false,
"alwaysUpdateLinks": true "alwaysUpdateLinks": true,
"defaultViewMode": "preview",
"autoConvertHtml": false,
"strictLineBreaks": false
} }

View File

@ -2,5 +2,5 @@
"theme": "obsidian", "theme": "obsidian",
"accentColor": "#745eff", "accentColor": "#745eff",
"interfaceFontFamily": "", "interfaceFontFamily": "",
"baseFontSize": 18 "baseFontSize": 20
} }

View File

@ -1,3 +1,5 @@
[ [
"templater-obsidian" "templater-obsidian",
"table-extended",
"obsidian-columns"
] ]

View File

@ -25,6 +25,6 @@
"audio-recorder": false, "audio-recorder": false,
"workspaces": false, "workspaces": false,
"file-recovery": true, "file-recovery": true,
"publish": false, "publish": true,
"sync": false "sync": false
} }

View File

@ -16,5 +16,6 @@
"bookmarks", "bookmarks",
"outline", "outline",
"word-count", "word-count",
"file-recovery" "file-recovery",
"publish"
] ]

View File

@ -1,5 +1,5 @@
{ {
"collapse-filter": true, "collapse-filter": false,
"search": "", "search": "",
"showTags": false, "showTags": false,
"showAttachments": false, "showAttachments": false,
@ -7,16 +7,16 @@
"showOrphans": true, "showOrphans": true,
"collapse-color-groups": true, "collapse-color-groups": true,
"colorGroups": [], "colorGroups": [],
"collapse-display": true, "collapse-display": false,
"showArrow": false, "showArrow": false,
"textFadeMultiplier": 0, "textFadeMultiplier": 0,
"nodeSizeMultiplier": 1, "nodeSizeMultiplier": 1.24399571927453,
"lineSizeMultiplier": 1, "lineSizeMultiplier": 3.23998535541286,
"collapse-forces": true, "collapse-forces": true,
"centerStrength": 0.518713248970312, "centerStrength": 0.518713248970312,
"repelStrength": 10, "repelStrength": 10,
"linkStrength": 1, "linkStrength": 1,
"linkDistance": 250, "linkDistance": 250,
"scale": 1.9042482571987516, "scale": 0.6174207201407237,
"close": false "close": true
} }

View File

@ -0,0 +1,18 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var V=Object.create;var w=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,W=Object.prototype.hasOwnProperty;var b=n=>w(n,"__esModule",{value:!0});var _=(n,t)=>{b(n);for(var e in t)w(n,e,{get:t[e],enumerable:!0})},K=(n,t,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of z(t))!W.call(n,l)&&l!=="default"&&w(n,l,{get:()=>t[l],enumerable:!(e=q(t,l))||e.enumerable});return n},N=n=>K(b(w(n!=null?V(j(n)):{},"default",n&&n.__esModule&&"default"in n?{get:()=>n.default,enumerable:!0}:{value:n,enumerable:!0})),n);var p=(n,t,e)=>new Promise((l,i)=>{var r=a=>{try{o(e.next(a))}catch(u){i(u)}},s=a=>{try{o(e.throw(a))}catch(u){i(u)}},o=a=>a.done?l(a.value):Promise.resolve(a.value).then(r,s);o((e=e.apply(n,t)).next())});_(exports,{ColumnInsertModal:()=>v,default:()=>x});var g=N(require("obsidian"));var L=N(require("obsidian")),J=n=>n=="yes"||n=="true",Q=(n,t)=>{if(t=="string")return n;if(t=="boolean")return J(n);if(t=="number")return parseFloat(n)};function E(n,t,e,l){let i=new L.Setting(n).setName(t[1].name).setDesc(t[1].desc);typeof t[1].value=="boolean"?i.addToggle(r=>r.setValue(e).onChange(s=>{l(s,t[0])})):i.addText(r=>r.setPlaceholder(String(t[1].value)).setValue(String(e)).onChange(s=>{l(Q(s,typeof t[1].value),t[0])}))}function I(n,t,e){let{containerEl:l}=n;l.empty(),l.createEl("h2",{text:"Settings for "+e});let i=Object.entries(t);for(let r of i)E(l,r,n.plugin.settings[r[0]].value,(s,o)=>{n.plugin.settings[o].value=s,n.plugin.saveSettings()})}function A(n,t){return p(this,null,function*(){return new Promise((e,l)=>{n.settings=t,n.loadData().then(i=>{i&&Object.entries(i).forEach(s=>{n.settings[s[0]].value=s[1]})}).then(e).catch(l)})})}function D(n,t){return p(this,null,function*(){let e={};Object.entries(n.settings).forEach(l=>{e[l[0]]=l[1].value,l[1].onChange(l[1].value)}),yield n.saveData(e)})}var X="Obsidian Columns",T="col",P=T+"-md",Y="!!!",O="===";var k="--obsidian-columns-min-width",G="--obsidian-columns-def-span",Z="`",M={wrapSize:{value:100,name:"Minimum width of column",desc:"Columns will have this minimum width before wrapping to a new row. 0 disables column wrapping. Useful for smaller devices",onChange:n=>{document.querySelector(":root").style.setProperty(k,n.toString()+"px")}},defaultSpan:{value:1,name:"The default span of an item",desc:"The default width of a column. If the minimum width is specified, the width of the column will be multiplied by this setting.",onChange:n=>{document.querySelector(":root").style.setProperty(G,n.toString())}}},H=(n,t=["`"],e=O)=>{let l=n.split(`
`),i=!1;e:for(let r of l)for(let s of t){if(r.contains(s))break e;if(r==e){let o=n.split(e+`
`);if(o.length>1)return{settings:o[0],source:o.slice(1).join(e+`
`)};break e}}return{settings:"",source:n}},B=n=>{let t={};return n.split(`
`).map(e=>e.split(";")).reduce((e,l)=>(e.push(...l),e)).map(e=>e.split("=").map(l=>l.trim()).slice(0,2)).forEach(e=>{t[e[0]]=e[1]}),t},$=n=>{let t=0,e=n.split("");for(let l of e)if(l==Z)t++;else break;return t},ee=n=>{let t=n.split(`
`),e=[],l=0,i=0,r=[];for(let s of t){let o=$(s);if(i=o<3?0:o,l==0&&i==0&&s.startsWith(O)){e.push(r.join(`
`)),r=[];continue}else l==0?l=i:l==i&&(l=0);r.push(s)}return e.push(r.join(`
`)),e},F=n=>parseFloat(n.split("").filter(t=>"0123456789.".contains(t)).join("")),x=class extends g.Plugin{constructor(){super(...arguments);this.generateCssString=t=>{let e={};return e.flexGrow=t.toString(),e.flexBasis=(this.settings.wrapSize.value*t).toString()+"px",e.width=(this.settings.wrapSize.value*t).toString()+"px",e};this.applyStyle=(t,e)=>{Object.assign(t.style,e)};this.processChild=t=>{t.firstChild!=null&&"tagName"in t.firstChild&&t.firstChild.tagName=="BR"&&t.removeChild(t.firstChild);let e=t;for(;e!=null;)"style"in e&&(e.style.marginTop="0px"),e=e.firstChild;let l=t;for(;l!=null;)"style"in l&&(l.style.marginBottom="0px"),l=l.lastChild}}onload(){return p(this,null,function*(){yield this.loadSettings(),this.addSettingTab(new R(this.app,this)),this.registerMarkdownCodeBlockProcessor(P,(e,l,i)=>{let r=H(e),s=B(r.settings);e=r.source;let o=i.sourcePath,a=l.createDiv(),u=new g.MarkdownRenderChild(a);if(i.addChild(u),g.MarkdownRenderer.renderMarkdown(e,a,o,u),s.flexGrow!=null){let d=parseFloat(s.flexGrow),f=this.generateCssString(d);delete f.width,this.applyStyle(a,f)}if(s.height!=null){let d={};d.height=s.height.toString(),d.overflow="scroll",this.applyStyle(a,d)}if(s.textAlign!=null){let d={};d.textAlign=s.textAlign,this.applyStyle(a,d)}}),this.registerMarkdownCodeBlockProcessor(T,(e,l,i)=>p(this,null,function*(){let r=H(e),s=B(r.settings),o=ee(r.source);console.log(o);for(let a of o){let u=i.sourcePath,d=createDiv(),f=new g.MarkdownRenderChild(d);i.addChild(f);let C=g.MarkdownRenderer.renderMarkdown(a,d,u,f),m=l.createEl("div",{cls:"columnParent"});if(Array.from(d.children).forEach(c=>{let h=m.createEl("div",{cls:"columnChild"}),y=new g.MarkdownRenderChild(h);i.addChild(y),this.applyStyle(h,this.generateCssString(this.settings.defaultSpan.value)),h.appendChild(c),c.classList.contains("block-language-"+P)&&c.childNodes[0].style.flexGrow!=""&&(h.style.flexGrow=c.childNodes[0].style.flexGrow,h.style.flexBasis=c.childNodes[0].style.flexBasis,h.style.width=c.childNodes[0].style.flexBasis),this.processChild(c)}),s.height!=null){let c=s.height;if(c=="shortest"){yield C;let h=Math.min(...Array.from(m.children).map(S=>S.childNodes[0]).map(S=>F(getComputedStyle(S).height)+F(getComputedStyle(S).lineHeight))),y={};y.height=h+"px",y.overflow="scroll",Array.from(m.children).map(S=>S.childNodes[0]).forEach(S=>{this.applyStyle(S,y)})}else{let h={};h.height=c,h.overflow="scroll",this.applyStyle(m,h)}}if(s.textAlign!=null){let c={};c.textAlign=s.textAlign,this.applyStyle(m,c)}}})),this.addCommand({id:"insert-column-wrapper",name:"Insert column wrapper",editorCallback:(e,l)=>{new v(this.app,i=>{let r=i.numberOfColumns.value,s="````col\n";for(let o=0;o<r;o++)s+="```col-md\nflexGrow=1\n===\n# Column "+o+"\n```\n";s+="````\n",e.replaceSelection(s)}).open()}}),this.addCommand({id:"insert-quick-column-wrapper",name:"Insert quick column wrapper",editorCallback:(e,l)=>{let i=e.getSelection(),r=e.getCursor(),s="````col\n```col-md\nflexGrow=1\n===\n"+i+"\n```\n````\n";if(e.replaceSelection(s),i==="")e.setCursor({line:r.line+4,ch:0});else{let o=i.split(`
`).length;e.setCursor({line:r.line+4+o-1,ch:i.length-i.lastIndexOf(`
`)-1})}}}),this.addCommand({id:"insert-column",name:"Insert column",editorCallback:(e,l)=>{let i=e.getSelection(),r=e.getCursor(),s;if(i==="")s="```col-md\nflexGrow=1\n===\n# New Column\n\n```",e.replaceSelection(s),e.setCursor({line:r.line+4,ch:0});else{s="```col-md\nflexGrow=1\n===\n"+i+"\n```",e.replaceSelection(s);let o=i.split(`
`).length;e.setCursor({line:r.line+o+2,ch:i.length-i.lastIndexOf(`
`)-1})}}});let t=(e,l)=>{for(let i of Array.from(e.children))if(i!=null&&!(i.nodeName!="UL"&&i.nodeName!="OL"))for(let r of Array.from(i.children)){if(r==null)continue;if(!r.textContent.trim().startsWith(Y+T)){t(r,l);continue}i.removeChild(r);let s=e.createEl("div",{cls:"columnParent"}),o=new g.MarkdownRenderChild(s);l.addChild(o);let a=r.querySelector("ul, ol");if(a!=null)for(let u of Array.from(a.children)){let d=s.createEl("div",{cls:"columnChild"}),f=new g.MarkdownRenderChild(d);l.addChild(f);let C=parseFloat(u.textContent.split(`
`)[0].split(" ")[0]);isNaN(C)&&(C=this.settings.defaultSpan.value),this.applyStyle(d,this.generateCssString(C));let m=!1;t(u,l);for(let c of Array.from(u.childNodes))m&&d.appendChild(c),c.nodeName=="#text"&&(m=!0);this.processChild(d)}}};this.registerMarkdownPostProcessor((e,l)=>{t(e,l)})})}onunload(){}loadSettings(){return p(this,null,function*(){yield A(this,M);let t=document.querySelector(":root");console.log(this.settings.wrapSize.value.toString()),t.style.setProperty(k,this.settings.wrapSize.value.toString()+"px"),t.style.setProperty(G,this.settings.defaultSpan.value.toString())})}saveSettings(){return p(this,null,function*(){yield D(this,M)})}},U={numberOfColumns:{value:2,name:"Number of Columns",desc:"Number of Columns to be made"}},v=class extends g.Modal{constructor(t,e){super(t);this.onSubmit=e}onOpen(){let{contentEl:t}=this;t.createEl("h1",{text:"Create a Column Wrapper"});let e=U,l=Object.entries(U);for(let i of l)E(t,i,"",(r,s)=>{e[s].value=r});new g.Setting(t).addButton(i=>i.setButtonText("Submit").setCta().onClick(()=>{this.close(),this.onSubmit(e)}))}onClose(){let{contentEl:t}=this;t.empty()}},R=class extends g.PluginSettingTab{constructor(t,e){super(t,e);this.plugin=e}display(){I(this,M,X)}};

View File

@ -0,0 +1,10 @@
{
"id": "obsidian-columns",
"name": "Obsidian Columns",
"minAppVersion": "0.12.0",
"description": "Allows you to create columns in Obsidian Markdown",
"author": "Trevor Nichols",
"authorUrl": "https://github.com/tnichols217/obsidian-columns",
"isDesktopOnly": false,
"version": "1.5.2"
}

View File

@ -0,0 +1,126 @@
:root {
--obsidian-columns-gap: 20px;
--obsidian-columns-padding: 15px 20px;
--obsidian-columns-min-width: 100px;
--obsidian-columns-def-span: 1;
}
div[data-callout="col"].callout,
div[data-callout^="col-md"].callout {
background-color: rgba(0, 0, 0, 0);
padding: 0 0 0 0;
border-style: none;
}
.columnParent, div[data-callout="col"].callout > div.callout-content {
display: flex !important;
padding: var(--obsidian-columns-padding);
flex-wrap: wrap;
gap: var(--obsidian-columns-gap);
white-space: normal;
}
div[data-callout="col"].callout > div.callout-title, div[data-callout^="col-md"].callout > div.callout-title {
display: none;
}
.cm-preview-code-block .admonition-content .columnParent p {
white-space: pre-wrap;
}
.columnChild, div[data-callout="col"].callout > div.callout-content > * {
flex-grow: var(--obsidian-columns-def-span);
flex-basis: calc(var(--obsidian-columns-min-width) * var(--obsidian-columns-def-span));
width: calc(var(--obsidian-columns-min-width) * var(--obsidian-columns-def-span));
}
div[data-callout="col"].callout > div.callout-content > div[data-callout^="col-md" ].callout {
flex-grow: var(--obsidian-columns-custom-span);
flex-basis: calc(var(--obsidian-columns-min-width) * var(--obsidian-columns-custom-span));
width: calc(var(--obsidian-columns-min-width) * var(--obsidian-columns-custom-span));
background-color: rgba(0, 0, 0, 0);
padding: 0 0 0 0;
border-style: none;
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-0.5" ].callout {
--obsidian-columns-custom-span: 0.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-1" ].callout,
div[data-callout="col"].callout > div.callout-content > div[data-callout="col-md" ].callout {
--obsidian-columns-custom-span: 1
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-1.5" ].callout {
--obsidian-columns-custom-span: 1.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-2" ].callout {
--obsidian-columns-custom-span: 2
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-2.5" ].callout {
--obsidian-columns-custom-span: 2.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-3" ].callout {
--obsidian-columns-custom-span: 3
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-3.5" ].callout {
--obsidian-columns-custom-span: 3.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-4" ].callout {
--obsidian-columns-custom-span: 4
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-4.5" ].callout {
--obsidian-columns-custom-span: 4.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-5" ].callout {
--obsidian-columns-custom-span: 5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-5.5" ].callout {
--obsidian-columns-custom-span: 5.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-6" ].callout {
--obsidian-columns-custom-span: 6
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-6.5" ].callout {
--obsidian-columns-custom-span: 6.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-7" ].callout {
--obsidian-columns-custom-span: 7
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-7.5" ].callout {
--obsidian-columns-custom-span: 7.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-8" ].callout {
--obsidian-columns-custom-span: 8
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-8.5" ].callout {
--obsidian-columns-custom-span: 8.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-9" ].callout {
--obsidian-columns-custom-span: 9
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-9.5" ].callout {
--obsidian-columns-custom-span: 9.5
}
div[data-callout="col"].callout > div.callout-content > div[data-callout$="-10" ].callout {
--obsidian-columns-custom-span: 10
}

12880
fp/.obsidian/plugins/table-extended/main.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,10 @@
{
"id": "table-extended",
"name": "Table Extended",
"version": "1.6.1",
"minAppVersion": "0.12.0",
"description": "Enable extended table support with MultiMarkdown 6 syntax",
"author": "AidenLx",
"authorUrl": "https://github.com/AidenLx/",
"isDesktopOnly": false
}

185
fp/.obsidian/workspace.json vendored Normal file
View File

@ -0,0 +1,185 @@
{
"main": {
"id": "a61451a8c5001773",
"type": "split",
"children": [
{
"id": "1ae4bfe7bb551ca1",
"type": "tabs",
"children": [
{
"id": "d3a2cb4690ca618a",
"type": "leaf",
"state": {
"type": "graph",
"state": {}
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "e4b9e2d7c5d13204",
"type": "split",
"children": [
{
"id": "9edcda04643fcae1",
"type": "tabs",
"children": [
{
"id": "5bd1035a5585fbea",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical"
}
}
},
{
"id": "43c9f56d675ae751",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
}
}
},
{
"id": "07bde3fd9daf269e",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {}
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"right": {
"id": "75cf567121b661bb",
"type": "split",
"children": [
{
"id": "cb4ecbabc2562514",
"type": "tabs",
"children": [
{
"id": "8b28a15737bcc1bd",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
}
}
},
{
"id": "d377ffdb958e1377",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"linksCollapsed": false,
"unlinkedCollapsed": true
}
}
},
{
"id": "b8cbcc5851c92334",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true
}
}
},
{
"id": "b631cd80a252e270",
"type": "leaf",
"state": {
"type": "outline",
"state": {}
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"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,
"publish:Publish changes...": false
}
},
"active": "d3a2cb4690ca618a",
"lastOpenFiles": [
"Data/Collections.md",
"Data/Collections/HashMap.md",
"Data/Product",
"Data/Untitled.md",
"Data/Sum",
"Data/Collections/HashSet.md",
"Data/Collections/Set.md",
"Data/Collections/List.md",
"Data/Collections/Map.md",
"Data/Collections",
"Language/Row Types.md",
"Language/Row Types/Variant.md",
"Language/Row Types/Record.md",
"Data/Product/Tuple.md",
"Language/Row Types",
"Data/Sum/Either.md",
"Language/Functions.md",
"Language/Functions/Defining/Guard Clause.md",
"Language/Typeclasses.md",
"Language/Type Signature.md",
"Class/Monoid.md",
"Class/Semigroup.md",
"Class/Math/EuclideanRing.md",
"Class/Math/Semiring.md",
"Class/Math/DivisionRing.md",
"Class/Math/Ring.md",
"Class/Semiring.md",
"Class/Math",
"Class/Foldable.md",
"Terminology/Purity.md",
"Language/Expressions/do notation.md",
"Monads/Classes/Stack-safe recursion",
"Monads/Classes/Early Return",
"Monads/Classes/State",
"Monads/Classes/F",
"Monads/Classes/Error Handling",
"Untitled 1.canvas",
"Untitled.canvas"
]
}

0
fp/Class/Alt.md Normal file
View File

0
fp/Class/Alternative.md Normal file
View File

0
fp/Class/Applicative.md Normal file
View File

0
fp/Class/Bind.md Normal file
View File

0
fp/Class/Foldable.md Normal file
View File

View File

@ -34,7 +34,7 @@ add 1 <$> Nothing
See also: See also:
- [[Bind]] - [[Bind]]
- [[Show]] - [[Show]]
- [[compose]] - [[Functions/Composition|compose]]
- [[do notation]] - [[do notation]]
```haskell ```haskell
import Node.FS.Sync (readTextFile, writeTextFile) import Node.FS.Sync (readTextFile, writeTextFile)

View File

View File

0
fp/Class/Math/Ring.md Normal file
View File

View File

0
fp/Class/Monad.md Normal file
View File

0
fp/Class/Monoid.md Normal file
View File

0
fp/Class/Plus.md Normal file
View File

0
fp/Class/Semigroup.md Normal file
View File

0
fp/Class/Show.md Normal file
View File

0
fp/Data/Boolean.md Normal file
View File

8
fp/Data/Collections.md Normal file
View File

@ -0,0 +1,8 @@
- [[Array]]
- [[List]]
- [[Set]]
- [[HashSet]]
- [[HashMap]]
- [[Map]]

View File

View File

View File

View File

View File

0
fp/Data/Number.md Normal file
View File

0
fp/Data/Product/Tuple.md Normal file
View File

0
fp/Data/Sum/Either.md Normal file
View File

View File

View File

View File

View File

@ -0,0 +1,108 @@
Pattern matching
```haskell
case <expr> of
<arm>+
```
where `arm` is:
```haskell
<pattern> -> <expr>
```
`pattern` can be:
- [[Data Structures/data|data]] constructors
- [[Records|record]] literals, containing patterns
- integer & number literals
- string literals
- array literals, containing patterns
- wildcard `_`
### Guard Clauses
Case arms can have [[Functions/Defining/Guard Clause|guard clauses]] like [[Functions|function]] definitions:
```haskell
case _ of
"" -> Nothing
s | String.Util.startsWith "/" -> Just s
| otherwise -> Nothing
```
### Examples
Match on `Int` when zero
```haskell
nonzeroInt :: Int -> Maybe Int
nonzeroInt n =
case n of
0 -> Nothing
n' -> Just n'
```
Match on [[Arity|nullary]] [[Data Structures/data|data]] constructors:
```haskell
data Letter = A | B | C
letterToString :: Letter -> String
letterToString l =
case l of
A -> "a"
B -> "b"
C -> "c"
```
Match on [[Arity|unary]] [[Data Structures/data|data]] constructors:
```haskell
isJust :: forall a. Maybe a -> Boolean
isJust m =
case m of
Just a -> true
Nothing -> false
```
Match on [[Arity|binary+]] [[Data Structures/data|data]] constructors:
```haskell
data ComplexDataType = Complex Int Int String String
complex :: ComplexDataType -> String
complex m =
case m of
Complex a b c d -> (show a) <> (show b) <> c <> d
```
Match on a record field that is `Maybe`, continuing if the field is `Just`
```haskell
unMaybeFirstName :: {firstName :: Maybe String} -> Maybe {firstName :: String}
unMaybeFirstName r =
case r of
{firstName: Just fn} -> Just {firstName: fn}
_ -> Nothing
```
Match on an array of `a` into [[Either|either]]:
- [[Maybe|zero or one]] `a`
- an [[Array]] of 2 or more `a`s
```haskell
zeroOneOrMore ::
forall a
. Array a
-> Either (Maybe a) (Array a)
zeroOneOrMore a =
case a of
[] -> Left Nothing
[a] -> Left (Just a)
_ -> Right a
```
Deserialize strings literals into a [[Data Structures/data|data structure]]
```haskell
data Animal = Dog | Cat | Giraffe
animalFromString :: String -> Maybe Animal
animalFromString s =
case s of
"dog" -> Just Dog
"cat" -> Just Cat
"giraffe" -> Just Giraffe
_ -> Nothing
```

View File

View File

View File

@ -1,204 +1 @@
## Applying The backbone of functional programming. Functions can be constants, transform [[Data Structures|data]], perform [[Effect|effects]] and much more.
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))

View File

@ -0,0 +1,59 @@
When 2 or more expressions are separated by whitespace, the left-most expression is a [[Functions|function]] and the others are arguments to it.
`````col
````col-md
#### Purescript
```haskell
Number.pow 2.0 10.0
```
````
````col-md
#### JS Equivalent
```javascript
Math.pow(2.0, 10.0)
```
````
`````
`````col
````col-md
```haskell
toString a
```
````
````col-md
```javascript
a.toString()
```
````
`````
`````col
````col-md
```haskell
intercalate ", " ["a", "b", "c"]
```
````
````col-md
```javascript
["a", "b", "c"].join(", ")
```
````
`````
`````col
````col-md
```haskell
intercalate
", "
["a", "b", "c"]
```
````
````col-md
```javascript
["a", "b", "c"]
.join(", ")
```
````
`````
![[Infix Operators#Infix Position|infix position]]

View File

@ -0,0 +1,32 @@
The most common pattern by far; piping the output of a [[Functions|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
```

View File

@ -0,0 +1,46 @@
[[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
> ```

View File

@ -0,0 +1,67 @@
The components of a [[Functions|function]] definition:
- [[Type Signature|type signature]] (optional)
- 1 or more "implementations" of the type signature, each with
- function name
- 0 or more arguments
- return expression
### Name
function names can contain any alphanumeric character, `_`, `'` but the first character must be a lowercase alpha or `_`.
### Arguments
Arguments are space-separated variable names between the function name and `=`.
For example, 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.
For example `a + b` is the body in:
```haskell
add a b = a + b
```
### Examples
A constant (function with 0 arguments)
```haskell
a :: String
a = ""
```
A function with a `String` argument, returning a `String`. The `String` argument is bound to `s` in the return expression `s <> ""`.
```haskell
a :: String -> String
a s = s <> "."
```
> [!tip]
> The simpler language "String to String" is often used instead of ".. with a String argument, returning a String."
>
> You can replace the function arrow `->` with the word "to"; For example `f :: a -> b -> c` is said as "f is a to b to c."
An implementation of fizzbuzz of type `Int` to `Maybe String`.
The body uses [[let .. in ..]] to define 2 helper functions:
- `divisible :: Int -> Boolean`
- `go :: Maybe String`
Returns `go`.
```haskell
fizzBuzz :: Int -> Maybe String
fizzBuzz n =
let
divisible a = n `mod` a == 0
go
| divisible 2 && divisible 5 = Just "fizzbuzz"
| divisible 2 = Just "fizz"
| divisible 5 = Just "buzz"
| otherwise = Nothing
in
go
```

View File

@ -0,0 +1,56 @@
Single [[Functions|Functions]] [[Defining/Pattern Matching|implementations]] may have 1 or more guard clauses.
> [!info]
> [[case .. of]] expressions can also use guard clauses.
These allow functions to switch on boolean expressions based on the inputs, and can often take up less space than explicit [[Expressions/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.
### Example
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`.
> [!tip]
> `otherwise` is simply an alias for `true`, specifically for better-reading fallthrough guard patterns.
Much less often, but occasionally useful is the ability to structurally pattern match in a guard clause:
```haskell
ensureLeadingSlashM :: Maybe String -> String
ensureLeadingSlashM mstr
| Just s <- mstr, String.Util.startsWith "/" s = s
| otherwise = ""
```
Here the bit `Just s <- mstr` is saying "when `mstr` is `Just s`..."
then `String.Util.startsWith "/" s` says "and `s` starts with `"/"`..."
`| Just s <- mstr, startsWith "/" s = s`
"when `mstr` is `Just s` and `s` starts with `"/"`, return s"
`| otherwise = ""`
otherwise return `""`
You can have any number of comma-separated guard bindings before the last boolean expression.

View File

@ -0,0 +1,28 @@
[[Functions]] may have multiple implementations that change behavior based on the shape of the arguments.
> [!note]
> You can always replace this with a [[case .. of|case expression]].
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
```

View File

@ -0,0 +1,2 @@
<div style="width: 100px; height: 100px; background: white;">
</div>

View File

@ -1,107 +1,18 @@
Infix operators are symbols that alias binary (2-argument) [[Functions|functions]]. Infix operators are [[Functions|functions]] of 2 arguments placed between their arguments, rather than before both arguments like regular 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 ```haskell
a + b == c a $ b
a + b
a >>= b
-- ...
``` ```
this behaves how you'd expect; this is equivalent to ### Infix Position
Arbitrary [[Functions|functions]] can also be [[Applying|applied]] in an infix position by wrapping them in backticks:
```haskell ```haskell
((a + b) == c) 3.0 `mod` 2.0 -- 1.0
10.0 `mod` 1.0 -- 0.0
1.0 `div` 2.0 -- 0.5
1.0 `Number.(/)` 2.0 -- 0.5
2.0 `Number.pow` 3.0 -- 8.0
``` ```
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.

View File

@ -0,0 +1,15 @@
[[Infix Operators]] are left-, right- or non-associative _(`infixl`, `infixr`, `infix` respectively)_
When multiple infix operators with the same associativity & precedence are chained, associativity tells the language how to group the expressions.
e.g. `&&` is right-associative, while `*` is left associative:
```haskell
a && b && c
-- interpreted as
(a && (b && c))
a * b * c
-- interpreted as
((a * b) * c)
```

View File

@ -0,0 +1,8 @@
[[Infix Operators]] commonly used when applying & composing functions
|Operator|Description|Associativity|Precedence|Defined As|
|--|--|--|--|--|
|`$`|function application|right|0|[`Data.Function.apply`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Function#v:($))|
|`#`|flipped function application|left|1|[`Data.Function.applyFlipped`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Function#v:(#))|
|`<<<`|function composition|right|9|[`Control.Category.compose`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Category#v:(%3C%3C%3C))|
|`>>>`|flipped function composition|right|9|[`Control.Category.composeFlipped`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Category#v:(%3E%3E%3E))|

View File

@ -0,0 +1,29 @@
[[Infix Operators]] used for [[Boolean|boolean]] algebra.
> [!info]
> `&&` and `||` become short-circuiting when used on functions, e.g. `Unit -> Boolean`:
>
> ```haskell
> a :: Unit -> Boolean
> a _ = false
>
> b :: Unit -> Boolean
> b _ = unsafeCrashWith "uh-oh!"
>
> c :: Unit -> Boolean
> c = a && b
>
> d :: Unit -> Boolean
> d = c unit
> ```
|Operator|Description|Associativity|Precedence|Defined As|
|--|--|--|--|--|
|<code>&vert;&vert;</code>|boolean OR|right|2|[`Data.HeytingAlgrebra.disj`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.HeytingAlgebra#v:(||))
|`&&`|boolean AND|right|3|[`Data.HeytingAlgrebra.conj`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.HeytingAlgebra#v:(&&))|
|`==`|equals|not|4|[`Data.Eq.eq`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Eq#v:(==))|
|`/=`|not equals|||[`Data.Eq.notEq`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Eq#v:(/=))|
|`>`|greater than|||[`Data.Ord.greaterThan`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Ord#v:(>))|
|`<`|less than|||[`Data.Ord.lessThan`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Ord#v:(<))|
|`>=`|greater than or equal|||[`Data.Ord.greaterThanOrEq`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Ord#v:(>=))|
|`<=`|less than or equal|||[`Data.Ord.lessThanOrEq`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Ord#v:(<=))|

View File

@ -0,0 +1,15 @@
|Operator|Description|Associativity|Precedence|Defined As|
|--|--|--|--|--|
|`<>`|append|right|5|[`Data.Semigroup.append`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Semigroup#v:(%3C%3E))|
|`<$>`|map|||
|`<#>`|flipped map|||
|`<*>`|apply (map using function of 2+ arguments)|||
|`>>=`|bind|left|1|[`Control.Bind.bind`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Bind#v:(%3E%3E=))|
|`=<<`|flipped bind|right|1|[`Control.Bind.bindFlipped`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Bind#v:(=<<))|
|`>=>`|point-free bind (kleisli composition)|right|1|[`Control.Bind.composeKleisli`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Bind#v:(>=>))|
|`<=<`|flipped point-free bind|right|1|[`Control.Bind.composeKleisliFlipped`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Bind#v:(<=<))|
|<code>&lt;&vert;&gt;</code>|Monadic "or;" try left, if bad then use right|right|3|[`Control.Alternative.alt`](https://pursuit.purescript.org/packages/purescript-control/docs/Control.Alt#v:(%3C%7C%3E))|
|`*>`|"evaluate left, then discard its return value and evaluate right"|left|4|[`Control.Apply.applySecond`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Apply#v:(*>))|
|`<*`|"evaluate left, then evaluate right and continue with the value left returned"|left|4|[`Control.Apply.applyFirst`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Control.Apply#v:(<*))|
|`$>`|"evaluate left, then discard its return value and continue with value"|left|4|[`Data.Functor.voidLeft`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Functor#v:(<$))
|`<$`|"evaluate right, then discard its return value and continue with value"|left|4|[`Data.Functor.voidRight`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Functor#v:($>))

View File

@ -0,0 +1,6 @@
|Operator|Description|Associativity|Precedence|Defined As|
|--|--|--|--|--|
|`+`|Addition|left|6|[`Data.Semiring.add`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Semiring#v:(+))|
|`*`|Multiplication|left|7|[`Data.Semiring.mul`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Semiring#v:(*))|
|`-`|Subtraction|left|6|[`Data.Ring.sub`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Ring#v:(-))|
|`/`|Division|left|7|[`Data.EuclideanRing.div`](https://pursuit.purescript.org/packages/purescript-prelude/docs/Data.Ring#v:(-))|

View File

@ -0,0 +1,25 @@
[[Infix Operators|Operators]] are defined with the keyword `infix`, `infixl` or `infixr`.
```haskell
infix <precedence> <fn> as <operator>
-- or
infixl -- ..
-- or
infixr -- ..
```
e.g.
```haskell
eq :: Int -> Int -> Boolean
eq = -- ...
add :: Int -> Int -> Int
add = -- ...
infixl 2 add as +
infixl 1 eq as ==
1 + 2 == 3
-- same as
(eq (add 1 2) 3)
```

View File

@ -0,0 +1,44 @@
Most commonly used [[Infix Operators]] have flipped variants, e.g.
- [[Functions#Composition|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|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.

View File

@ -0,0 +1,14 @@
[[Infix Operators|Operators]] must have a precedence, which tells the language in what order to group the expressions.
e.g. in this expression:
```haskell
a + b == c
```
this behaves how you'd expect; this is equivalent to
```haskell
((a + b) == c)
```
This is because the precedence of `+` (6) is higher than `==`'s (4), the grouping is first done around `a + b`.

0
fp/Language/Row Types.md Normal file
View File

View File

View File

View File

@ -0,0 +1,74 @@
Type signatures are written with [hindley-milner syntax](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system).
They take the form
```text
{function} :: {type variables} {constraints} {arguments} {return type}
```
where:
- `{function}` is the [[Functions|function]] name
- `{type variables}` defines a list of type variables that are initially unconstrained; they could be literally anything.
- `{constraints}` is a list of 0 or more [[Typeclasses|typeclass]] constraints that need to be met in order to apply the function
- `{arguments}` is a list of 0 or more arguments
- `{return type}` is the type returned by the function
### Type Variables
Type variables are a list of camelCase generic type parameters.
```text
forall a.
```
Defines 1 type variable `a`.
```text
forall a b c.
```
Defines 3 type variables `a`, `b` and `c`.
### Constraints
List of typeclass constraints that must be true in order to apply the function, separated by `=>`
```text
forall a. Show a => ..
```
for any `a` that is `Show`able
```text
forall a b. Show a => Eq b => ..
```
for any `a` and `b`, provided that `a` is `Show`able and `b` can be compared for `Eq`uality.
### Arguments
Function arguments, separated by `->`
```text
String
```
constant (function with 0 arguments) of type `String`
```text
a -> b
```
function from `a` to `b` (1 argument)
```text
a -> b -> c
```
function from `a` to `b` to `c` (2 arguments; `a` & `b`)
### Examples
```haskell
identity :: forall a. a -> a
```
`identity` is `a` to `a` for any `a`
```haskell
split :: String -> String -> String
```
split is `String` to `String` to `String`.
```haskell
sum :: forall f a. Foldable f => Semiring a => f a -> a
```
`sum` is `f` of `a` to `a`, for any collection<sup>[[Foldable]]</sup> `f` and any type supporting addition<sup>[[Semiring]]</sup> `a`

View File

View File

View File

View File

View File

View File

View File

View File

@ -1,12 +0,0 @@
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})`
}

View File

@ -1 +0,0 @@
<% tp.user.pursuit_link(tp.system.prompt("Path", "", true)) %>

9
fp/Terminology/Arity.md Normal file
View File

@ -0,0 +1,9 @@
"Arity" is the number of arguments:
arity|number of arguments
--|--
nullary|0
unary|1
binary|2
ternary|3
"arity of n"|n

0
fp/Terminology/Purity.md Normal file
View File

View File

@ -0,0 +1,13 @@
A property of [[Purity|pure]] [[Functions|functions]] that they can always be replaced by the expression they return.
For example `add` is referentially transparent, so
```haskell
a = add 1 3
```
could be replaced with
```haskell
a = 4
```
at design- or compile-time, because `add` always returns the same result and performs no observable side-effects.

3
lum/lum/.obsidian/app.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"promptDelete": false
}

1
lum/lum/.obsidian/appearance.json vendored Normal file
View File

@ -0,0 +1 @@
{}

View 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
lum/lum/.obsidian/core-plugins.json vendored Normal file
View 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
lum/lum/.obsidian/graph.json vendored Normal file
View 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,
"close": true
}

175
lum/lum/.obsidian/workspace.json vendored Normal file
View File

@ -0,0 +1,175 @@
{
"main": {
"id": "01749791f5cf7c0c",
"type": "split",
"children": [
{
"id": "d1222fc030931cbe",
"type": "tabs",
"children": [
{
"id": "fddaf66e771021a1",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "eng/systems/fly/analytics db.md",
"mode": "source",
"source": false
}
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "775365197c694ce1",
"type": "split",
"children": [
{
"id": "1776f9089e738aaa",
"type": "tabs",
"children": [
{
"id": "9e7c192b9f83e80b",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical"
}
}
},
{
"id": "26de1d6c7cef5d80",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
}
}
},
{
"id": "0849633ac8c056d6",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {}
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "1c0766675e9004b3",
"type": "split",
"children": [
{
"id": "f966312a0f09279f",
"type": "tabs",
"children": [
{
"id": "530ceb6f5887c3b0",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "eng/systems/fly/analytics db.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
}
}
},
{
"id": "60efe1152b312d28",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"file": "eng/systems/fly/analytics db.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
}
}
},
{
"id": "11527b0145c94893",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true
}
}
},
{
"id": "dd049f6ce1ab70c5",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "eng/systems/fly/analytics db.md"
}
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"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
}
},
"active": "9e7c192b9f83e80b",
"lastOpenFiles": [
"eng/code",
"eng/fly.md",
"eng/systems/fly/analytics db.md",
"eng/systems/fly/metabase.md",
"eng/systems/fly/db.md",
"eng/systems/fly/ui.md",
"eng/systems/fly/api.md",
"eng/systems/UpCloud/airbyte.md",
"eng/systems/fly",
"eng/systems/UpCloud/Untitled.md",
"eng/systems/UpCloud/gitea.md",
"eng/systems/AWS/Bedrock.md",
"eng/systems/UpCloud",
"eng/systems/AWS.md",
"eng/systems/AWS/Untitled.md",
"eng/systems/AWS",
"eng/systems",
"Orange.md",
"create a link.md",
"eng/Fruits.md",
"Welcome.md",
"biz",
"eng"
]
}

View File

@ -0,0 +1 @@
Used by API for LLM inference

View File

@ -0,0 +1,3 @@
airbyte.lum.ventures
using <https://git.orionkindel.com/lum/airbyte-minikube>

View File

@ -0,0 +1 @@
git.orionkindel.com

View File

View File

View File

View File

View File