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,
|
"livePreview": false,
|
||||||
"promptDelete": 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",
|
"theme": "obsidian",
|
||||||
"accentColor": "#745eff",
|
"accentColor": "#745eff",
|
||||||
"interfaceFontFamily": "",
|
"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,
|
"audio-recorder": false,
|
||||||
"workspaces": false,
|
"workspaces": false,
|
||||||
"file-recovery": true,
|
"file-recovery": true,
|
||||||
"publish": false,
|
"publish": true,
|
||||||
"sync": false
|
"sync": false
|
||||||
}
|
}
|
3
fp/.obsidian/core-plugins.json
vendored
3
fp/.obsidian/core-plugins.json
vendored
@ -16,5 +16,6 @@
|
|||||||
"bookmarks",
|
"bookmarks",
|
||||||
"outline",
|
"outline",
|
||||||
"word-count",
|
"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": "",
|
"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
|
||||||
}
|
}
|
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:
|
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)
|
||||||
|
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
|
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))
|
|
||||||
|
|
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]].
|
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.
|
|
||||||
|
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