forked from orion/obsidian
update
This commit is contained in:
parent
ebb7d92134
commit
3701b1e2f8
5
fp/.obsidian/app.json
vendored
5
fp/.obsidian/app.json
vendored
@ -17,5 +17,8 @@
|
||||
],
|
||||
"livePreview": false,
|
||||
"promptDelete": false,
|
||||
"alwaysUpdateLinks": true
|
||||
"alwaysUpdateLinks": true,
|
||||
"defaultViewMode": "preview",
|
||||
"autoConvertHtml": false,
|
||||
"strictLineBreaks": false
|
||||
}
|
2
fp/.obsidian/appearance.json
vendored
2
fp/.obsidian/appearance.json
vendored
@ -2,5 +2,5 @@
|
||||
"theme": "obsidian",
|
||||
"accentColor": "#745eff",
|
||||
"interfaceFontFamily": "",
|
||||
"baseFontSize": 18
|
||||
"baseFontSize": 20
|
||||
}
|
4
fp/.obsidian/community-plugins.json
vendored
4
fp/.obsidian/community-plugins.json
vendored
@ -1,3 +1,5 @@
|
||||
[
|
||||
"templater-obsidian"
|
||||
"templater-obsidian",
|
||||
"table-extended",
|
||||
"obsidian-columns"
|
||||
]
|
2
fp/.obsidian/core-plugins-migration.json
vendored
2
fp/.obsidian/core-plugins-migration.json
vendored
@ -25,6 +25,6 @@
|
||||
"audio-recorder": false,
|
||||
"workspaces": false,
|
||||
"file-recovery": true,
|
||||
"publish": false,
|
||||
"publish": true,
|
||||
"sync": false
|
||||
}
|
3
fp/.obsidian/core-plugins.json
vendored
3
fp/.obsidian/core-plugins.json
vendored
@ -16,5 +16,6 @@
|
||||
"bookmarks",
|
||||
"outline",
|
||||
"word-count",
|
||||
"file-recovery"
|
||||
"file-recovery",
|
||||
"publish"
|
||||
]
|
12
fp/.obsidian/graph.json
vendored
12
fp/.obsidian/graph.json
vendored
@ -1,5 +1,5 @@
|
||||
{
|
||||
"collapse-filter": true,
|
||||
"collapse-filter": false,
|
||||
"search": "",
|
||||
"showTags": false,
|
||||
"showAttachments": false,
|
||||
@ -7,16 +7,16 @@
|
||||
"showOrphans": true,
|
||||
"collapse-color-groups": true,
|
||||
"colorGroups": [],
|
||||
"collapse-display": true,
|
||||
"collapse-display": false,
|
||||
"showArrow": false,
|
||||
"textFadeMultiplier": 0,
|
||||
"nodeSizeMultiplier": 1,
|
||||
"lineSizeMultiplier": 1,
|
||||
"nodeSizeMultiplier": 1.24399571927453,
|
||||
"lineSizeMultiplier": 3.23998535541286,
|
||||
"collapse-forces": true,
|
||||
"centerStrength": 0.518713248970312,
|
||||
"repelStrength": 10,
|
||||
"linkStrength": 1,
|
||||
"linkDistance": 250,
|
||||
"scale": 1.9042482571987516,
|
||||
"close": false
|
||||
"scale": 0.6174207201407237,
|
||||
"close": true
|
||||
}
|
18
fp/.obsidian/plugins/obsidian-columns/main.js
vendored
Normal file
18
fp/.obsidian/plugins/obsidian-columns/main.js
vendored
Normal 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)}};
|
10
fp/.obsidian/plugins/obsidian-columns/manifest.json
vendored
Normal file
10
fp/.obsidian/plugins/obsidian-columns/manifest.json
vendored
Normal 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"
|
||||
}
|
126
fp/.obsidian/plugins/obsidian-columns/styles.css
vendored
Normal file
126
fp/.obsidian/plugins/obsidian-columns/styles.css
vendored
Normal 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
12880
fp/.obsidian/plugins/table-extended/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
10
fp/.obsidian/plugins/table-extended/manifest.json
vendored
Normal file
10
fp/.obsidian/plugins/table-extended/manifest.json
vendored
Normal 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
185
fp/.obsidian/workspace.json
vendored
Normal 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
0
fp/Class/Alt.md
Normal file
0
fp/Class/Alternative.md
Normal file
0
fp/Class/Alternative.md
Normal file
0
fp/Class/Applicative.md
Normal file
0
fp/Class/Applicative.md
Normal file
0
fp/Class/Bind.md
Normal file
0
fp/Class/Bind.md
Normal file
0
fp/Class/Foldable.md
Normal file
0
fp/Class/Foldable.md
Normal file
@ -34,7 +34,7 @@ add 1 <$> Nothing
|
||||
See also:
|
||||
- [[Bind]]
|
||||
- [[Show]]
|
||||
- [[compose]]
|
||||
- [[Functions/Composition|compose]]
|
||||
- [[do notation]]
|
||||
```haskell
|
||||
import Node.FS.Sync (readTextFile, writeTextFile)
|
||||
|
0
fp/Class/Math/DivisionRing.md
Normal file
0
fp/Class/Math/DivisionRing.md
Normal file
0
fp/Class/Math/EuclideanRing.md
Normal file
0
fp/Class/Math/EuclideanRing.md
Normal file
0
fp/Class/Math/Ring.md
Normal file
0
fp/Class/Math/Ring.md
Normal file
0
fp/Class/Math/Semiring.md
Normal file
0
fp/Class/Math/Semiring.md
Normal file
0
fp/Class/Monad.md
Normal file
0
fp/Class/Monad.md
Normal file
0
fp/Class/Monoid.md
Normal file
0
fp/Class/Monoid.md
Normal file
0
fp/Class/Plus.md
Normal file
0
fp/Class/Plus.md
Normal file
0
fp/Class/Semigroup.md
Normal file
0
fp/Class/Semigroup.md
Normal file
0
fp/Class/Show.md
Normal file
0
fp/Class/Show.md
Normal file
0
fp/Data/Boolean.md
Normal file
0
fp/Data/Boolean.md
Normal file
8
fp/Data/Collections.md
Normal file
8
fp/Data/Collections.md
Normal file
@ -0,0 +1,8 @@
|
||||
- [[Array]]
|
||||
- [[List]]
|
||||
|
||||
- [[Set]]
|
||||
- [[HashSet]]
|
||||
|
||||
- [[HashMap]]
|
||||
- [[Map]]
|
0
fp/Data/Collections/HashMap.md
Normal file
0
fp/Data/Collections/HashMap.md
Normal file
0
fp/Data/Collections/HashSet.md
Normal file
0
fp/Data/Collections/HashSet.md
Normal file
0
fp/Data/Collections/List.md
Normal file
0
fp/Data/Collections/List.md
Normal file
0
fp/Data/Collections/Map.md
Normal file
0
fp/Data/Collections/Map.md
Normal file
0
fp/Data/Collections/Set.md
Normal file
0
fp/Data/Collections/Set.md
Normal file
0
fp/Data/Number.md
Normal file
0
fp/Data/Number.md
Normal file
0
fp/Data/Product/Tuple.md
Normal file
0
fp/Data/Product/Tuple.md
Normal file
0
fp/Data/Sum/Either.md
Normal file
0
fp/Data/Sum/Either.md
Normal file
0
fp/Language/Data Structures/Records.md
Normal file
0
fp/Language/Data Structures/Records.md
Normal file
0
fp/Language/Data Structures/data.md
Normal file
0
fp/Language/Data Structures/data.md
Normal file
0
fp/Language/Data Structures/type.md
Normal file
0
fp/Language/Data Structures/type.md
Normal file
108
fp/Language/Expressions/case .. of.md
Normal file
108
fp/Language/Expressions/case .. of.md
Normal 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
|
||||
```
|
0
fp/Language/Expressions/do notation.md
Normal file
0
fp/Language/Expressions/do notation.md
Normal file
0
fp/Language/Expressions/if .. then .. else ...md
Normal file
0
fp/Language/Expressions/if .. then .. else ...md
Normal file
0
fp/Language/Expressions/let .. in ...md
Normal file
0
fp/Language/Expressions/let .. in ...md
Normal file
@ -1,204 +1 @@
|
||||
## 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))
|
||||
|
||||
The backbone of functional programming. Functions can be constants, transform [[Data Structures|data]], perform [[Effect|effects]] and much more.
|
59
fp/Language/Functions/Applying.md
Normal file
59
fp/Language/Functions/Applying.md
Normal 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]]
|
32
fp/Language/Functions/Composition.md
Normal file
32
fp/Language/Functions/Composition.md
Normal 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
|
||||
```
|
46
fp/Language/Functions/Currying.md
Normal file
46
fp/Language/Functions/Currying.md
Normal 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
|
||||
> ```
|
67
fp/Language/Functions/Defining.md
Normal file
67
fp/Language/Functions/Defining.md
Normal 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
|
||||
```
|
56
fp/Language/Functions/Defining/Guard Clause.md
Normal file
56
fp/Language/Functions/Defining/Guard Clause.md
Normal 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.
|
28
fp/Language/Functions/Defining/Pattern Matching.md
Normal file
28
fp/Language/Functions/Defining/Pattern Matching.md
Normal 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
|
||||
```
|
2
fp/Language/Functions/table.html
Normal file
2
fp/Language/Functions/table.html
Normal file
@ -0,0 +1,2 @@
|
||||
<div style="width: 100px; height: 100px; background: white;">
|
||||
</div>
|
@ -1,107 +1,18 @@
|
||||
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
|
||||
Infix operators are [[Functions|functions]] of 2 arguments placed between their arguments, rather than before both arguments like regular functions.
|
||||
|
||||
```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
|
||||
((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.
|
||||
|
15
fp/Language/Infix Operators/Associativity.md
Normal file
15
fp/Language/Infix Operators/Associativity.md
Normal 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)
|
||||
```
|
@ -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))|
|
@ -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>||</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:(<=))|
|
15
fp/Language/Infix Operators/Common Operators/Data.md
Normal file
15
fp/Language/Infix Operators/Common Operators/Data.md
Normal 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><|></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:($>))
|
6
fp/Language/Infix Operators/Common Operators/Math.md
Normal file
6
fp/Language/Infix Operators/Common Operators/Math.md
Normal 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:(-))|
|
25
fp/Language/Infix Operators/Defining.md
Normal file
25
fp/Language/Infix Operators/Defining.md
Normal 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)
|
||||
```
|
44
fp/Language/Infix Operators/Directionality.md
Normal file
44
fp/Language/Infix Operators/Directionality.md
Normal 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.
|
14
fp/Language/Infix Operators/Precedence.md
Normal file
14
fp/Language/Infix Operators/Precedence.md
Normal 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
0
fp/Language/Row Types.md
Normal file
0
fp/Language/Row Types/Record.md
Normal file
0
fp/Language/Row Types/Record.md
Normal file
0
fp/Language/Row Types/Variant.md
Normal file
0
fp/Language/Row Types/Variant.md
Normal file
74
fp/Language/Type Signature.md
Normal file
74
fp/Language/Type Signature.md
Normal 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`
|
0
fp/Monads/Classes/Early Return/MonadPlus.md
Normal file
0
fp/Monads/Classes/Early Return/MonadPlus.md
Normal file
0
fp/Monads/Classes/Error Handling/MonadError.md
Normal file
0
fp/Monads/Classes/Error Handling/MonadError.md
Normal file
0
fp/Monads/Classes/Error Handling/MonadThrow.md
Normal file
0
fp/Monads/Classes/Error Handling/MonadThrow.md
Normal file
0
fp/Monads/Classes/MonadAff.md
Normal file
0
fp/Monads/Classes/MonadAff.md
Normal file
0
fp/Monads/Classes/MonadEffect.md
Normal file
0
fp/Monads/Classes/MonadEffect.md
Normal file
0
fp/Monads/Classes/Stack-safe recursion/MonadRec.md
Normal file
0
fp/Monads/Classes/Stack-safe recursion/MonadRec.md
Normal file
0
fp/Monads/Classes/State/MonadAsk.md
Normal file
0
fp/Monads/Classes/State/MonadAsk.md
Normal file
0
fp/Monads/Classes/State/MonadReader.md
Normal file
0
fp/Monads/Classes/State/MonadReader.md
Normal file
0
fp/Monads/Classes/State/MonadState.md
Normal file
0
fp/Monads/Classes/State/MonadState.md
Normal file
0
fp/Monads/Classes/State/MonadTell.md
Normal file
0
fp/Monads/Classes/State/MonadTell.md
Normal file
0
fp/Monads/Classes/State/MonadWriter.md
Normal file
0
fp/Monads/Classes/State/MonadWriter.md
Normal 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})`
|
||||
}
|
@ -1 +0,0 @@
|
||||
<% tp.user.pursuit_link(tp.system.prompt("Path", "", true)) %>
|
9
fp/Terminology/Arity.md
Normal file
9
fp/Terminology/Arity.md
Normal 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
0
fp/Terminology/Purity.md
Normal file
13
fp/Terminology/Referential Transparency.md
Normal file
13
fp/Terminology/Referential Transparency.md
Normal 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
3
lum/lum/.obsidian/app.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"promptDelete": false
|
||||
}
|
1
lum/lum/.obsidian/appearance.json
vendored
Normal file
1
lum/lum/.obsidian/appearance.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{}
|
30
lum/lum/.obsidian/core-plugins-migration.json
vendored
Normal file
30
lum/lum/.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
lum/lum/.obsidian/core-plugins.json
vendored
Normal file
20
lum/lum/.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
lum/lum/.obsidian/graph.json
vendored
Normal file
22
lum/lum/.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,
|
||||
"close": true
|
||||
}
|
175
lum/lum/.obsidian/workspace.json
vendored
Normal file
175
lum/lum/.obsidian/workspace.json
vendored
Normal 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"
|
||||
]
|
||||
}
|
1
lum/lum/eng/systems/AWS/Bedrock.md
Normal file
1
lum/lum/eng/systems/AWS/Bedrock.md
Normal file
@ -0,0 +1 @@
|
||||
Used by API for LLM inference
|
3
lum/lum/eng/systems/UpCloud/airbyte.md
Normal file
3
lum/lum/eng/systems/UpCloud/airbyte.md
Normal file
@ -0,0 +1,3 @@
|
||||
airbyte.lum.ventures
|
||||
|
||||
using <https://git.orionkindel.com/lum/airbyte-minikube>
|
1
lum/lum/eng/systems/UpCloud/gitea.md
Normal file
1
lum/lum/eng/systems/UpCloud/gitea.md
Normal file
@ -0,0 +1 @@
|
||||
git.orionkindel.com
|
0
lum/lum/eng/systems/fly/analytics db.md
Normal file
0
lum/lum/eng/systems/fly/analytics db.md
Normal file
0
lum/lum/eng/systems/fly/api.md
Normal file
0
lum/lum/eng/systems/fly/api.md
Normal file
0
lum/lum/eng/systems/fly/db.md
Normal file
0
lum/lum/eng/systems/fly/db.md
Normal file
0
lum/lum/eng/systems/fly/metabase.md
Normal file
0
lum/lum/eng/systems/fly/metabase.md
Normal file
0
lum/lum/eng/systems/fly/ui.md
Normal file
0
lum/lum/eng/systems/fly/ui.md
Normal file
Loading…
Reference in New Issue
Block a user