SlideShare a Scribd company logo
Functional Concepts in C#
Or “Who the F# Wrote This?”
https://github.com/mrdrbob/sd-code-camp-2016
Thanks Sponsors!
Let’s Manage Expectations!
What this talk is
A gentle introduction to functional
paradigms using a language you may
already be familiar with.
A comparison between OOP and
functional styles
A discussion on language expectations
What this talk
isn’t
“OOP is dead!”
“Functional all the things!”
“All code should look exactly like
this!” (Spoiler: it probably shouldn’t)
Who I am
Bob Davidson
C# / Web Developer 11 years
Blend Interactive
A guy who is generally interested in
and learning about functional
programming concepts
https://github.com/mrdrbob
Who I am Not
A functional programming expert who
says things like:
“All told, a monad in X is just a
monoid in the category of
endofunctors of X, with product ×
replaced by composition of
endofunctors and unit set by the
identity endofunctor.”
-Saunders Mac Lane
Let’s Build a Parser!
A highly simplified JSON-like syntax for strings and integers.
Integers
One or more digits
Strings
Starts & ends with double quote.
Quotes can be escaped with slash.
Slash can be escaped with slash.
Can be empty.
Iteration 1.0
The IParser<TValue> Interface
public interface IParser<TValue>  {
bool  TryParse(string raw,  out TValue value);
}
IntegerParser
public class IntegerParser :  IParser<int>  {
public bool  TryParse(string raw,  out int value)  {
value  = 0;
int x  = 0;
List<char> buffer  = new List<char>();
while (x  < raw.Length && char.IsDigit(raw[x]))  {
buffer.Add(raw[x]);
x  += 1;
}
if (x  == 0)
return false;
//  Deal  with  it.
value  = int.Parse(new string(buffer.ToArray()));
return true;
}
}
IntegerParser
public class IntegerParser :  IParser<int>  {
public bool  TryParse(string raw,  out int value)  {
value  = 0;
int x  = 0;
List<char> buffer  = new List<char>();
while (x  < raw.Length && char.IsDigit(raw[x]))  {
buffer.Add(raw[x]);
x  += 1;
}
if (x  == 0)
return false;
value  = int.Parse(new string(buffer.ToArray()));
return true;
}
}
StringParser
public class StringParser :  IParser<string>  {
public bool  TryParse(string raw,  out string value)  {
value  = null;
int x  = 0;
if (x  == raw.Length || raw[x]  != '"')
return false;
x  += 1;
List<char> buffer  = new List<char>();
while (x  < raw.Length && raw[x]  != '"')  {
if (raw[x]  == '')  {
x  += 1;
if (x  == raw.Length)
return false;
if (raw[x]  == '')
buffer.Add(raw[x]);
else if (raw[x]  == '"')
buffer.Add(raw[x]);
else
return false;
}  else {
buffer.Add(raw[x]);
}
x  += 1;
}
if (x  == raw.Length)
return false;
x  += 1;
value  = new string(buffer.ToArray());
return true;
}
}
Possible Issues
public class StringParser :  IParser<string>  {
public bool  TryParse(string raw,  out string value)  {
value  = null;
int x  = 0;
if (x  == raw.Length || raw[x]  != '"')
return false;
x  += 1;
List<char> buffer  = new List<char>();
while (x  < raw.Length && raw[x]  != '"')  {
if (raw[x]  == '')  {
x  += 1;
if (x  == raw.Length)
return false;
if (raw[x]  == '')
buffer.Add(raw[x]);
else if (raw[x]  == '"')
buffer.Add(raw[x]);
else
return false;
}  else {
buffer.Add(raw[x]);
}
x  += 1;
}
if (x  == raw.Length)
return false;
x  += 1;
value  = new string(buffer.ToArray());
return true;
}
}
Repeated checks against
running out of input
Easily missed logic for
moving input forward
No way to see how much
input was consumed / how
much is left
Hard to understand at a
glance what is happening
public class IntegerParser :  IParser<int>  {
public bool  TryParse(string raw,  out int value)  {
value  = 0;
int x  = 0;
List<char> buffer  = new List<char>();
while (x  < raw.Length && char.IsDigit(raw[x]))  {
buffer.Add(raw[x]);
x  += 1;
}
if (x  == 0)
return false;
//  Deal  with  it.
value  = int.Parse(new string(buffer.ToArray()));
return true;
}
}
Rethinking the Parser
Make a little more generic / reusable
Break the process down into a series of rules which can be composed to make new
parsers from existing parsers
Build a framework that doesn’t rely on strings, but rather a stream of tokens
Iteration 2.0
Composition
[Picture of Legos Here]
One or More
Times
A Parser Built on Rules (Integer Parser)
[0-9]
Ignore Latter
Keep Latter
Zero or More Times
Any of these
NotKeep Latter
A Parser Built on Rules (String Parser)
“
 “
Keep Latter
 
Any of these
 “
“
A Set of Rules
Match Quote
Match Slash
Match Digit
Match Then Keep
Match Then Ignore
Match Any
Match Zero or More Times
Match One or More Times
Not
Rethinking the Source
Handle tokens other than chars (such as byte streams, pre-lexed tokens, etc)
Need the ability to continue parsing after a success
Need the ability to reset after a failure
Rethinking the Source
public interface ISource<Token>  {
Token Current {  get;  }
bool  HasMore {  get;  }
int CurrentIndex {  get;  }
void Move(int index);
}
public class StringSource :  ISource<char>  {
readonly  string  value;
int index;
public StringSource(string value)  {  this.value  = value;  }
public char Current  => value[index];
public int CurrentIndex  => index;
public bool  HasMore  => index  < value.Length;
public void Move(int index)  =>  this.index  =  index;
}
Creating a Rule
public interface IRule<Token,  TResult>  {
bool  TryParse(ISource<Token> source,  out TResult result);
}
Char Matches...
public class CharIsQuote :  IRule<char,  char>  {
public bool  TryParse(ISource<char> source,  out
char result)  {
result  = default(char);
if (!source.HasMore)
return false;
if (source.Current != '"')
return false;
result  = source.Current;
source.Move(source.CurrentIndex + 1);
return true;
}
}
public class CharIs :  IRule<char,  char>  {
readonly  char toMatch;
public CharIs(char toMatch)  {  this.toMatch  =
toMatch;  }
public bool  TryParse(ISource<char> source,  out char
result)  {
result  = default(char);
if (!source.HasMore)
return false;
if (source.Current != toMatch)
return false;
result  = source.Current;
source.Move(source.CurrentIndex + 1);
return true;
}
}
Char Matches...
public abstract class CharMatches :  IRule<char,  char>  {
protected abstract bool  IsCharMatch(char c);
public bool  TryParse(ISource<char> source,  out char result)  {
result  = default(char);
if (!source.HasMore)
return false;
if (!IsCharMatch(source.Current))
return false;
result  = source.Current;
source.Move(source.CurrentIndex + 1);
return true;
}
}
public class CharIsDigit :  CharMatches  {
protected override  bool  IsCharMatch(char c)  =>  char.IsDigit(c);
}
public class CharIs :  CharMatches  {
readonly  char toMatch;
public CharIs(char toMatch)  {  this.toMatch  = toMatch;  }
protected override  bool  IsCharMatch(char c)  =>  c  ==  toMatch;
}
First Match (or Any)
public class FirstMatch<Token,  TResult>  :  IRule<Token,  TResult>  {
readonly  IRule<Token,  TResult>[]  rules;
public FirstMatch(IRule<Token,  TResult>[]  rules)  {  this.rules  = rules;  }
public bool  TryParse(ISource<Token> source,  out TResult result)  {
foreach(var  rule  in  rules)  {
int originalIndex  = source.CurrentIndex;
if (rule.TryParse(source,  out  result))
return true;
source.Move(originalIndex);
}
result  = default(TResult);
return false;
}
}
Match Then... public abstract class MatchThen<Token,  TLeft,  TRight,  TOut>  :  IRule<Token,  TOut>  {
readonly  IRule<Token,  TLeft> leftRule;
readonly  IRule<Token,  TRight> rightRule;
protected abstract TOut Combine(TLeft leftResult,  TRight rightResult);
public MatchThen(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  {
this.leftRule  = leftRule;
this.rightRule  = rightRule;
}
public bool  TryParse(ISource<Token> source,  out TOut result)  {
int originalIndex  = source.CurrentIndex;
result  = default(TOut);
TLeft leftResult;
if (!leftRule.TryParse(source,  out  leftResult))  {
source.Move(originalIndex);
return false;
}
TRight rightResult;
if (!rightRule.TryParse(source,  out  rightResult))  {
source.Move(originalIndex);
return false;
}
result  = Combine(leftResult,  rightResult);
return true;
}
}
Match Then...
public class MatchThenKeep<Token,  TLeft,  TRight>  :  MatchThen<Token,  TLeft,  TRight,  TRight>  {
public MatchThenKeep(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  :  base(leftRule,  rightRule)  {  }
protected override  TRight Combine(TLeft leftResult,  TRight rightResult)  =>  rightResult;
}
public class MatchThenIgnore<Token,  TLeft,  TRight>  :  MatchThen<Token,  TLeft,  TRight,  TLeft>  {
public MatchThenIgnore(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  :  base(leftRule,  rightRule)  {  }
protected override  TLeft Combine(TLeft leftResult,  TRight rightResult)  =>  leftResult;
}
Invert Rule (Not)
public class Not<Token,  TResult>  :  IRule<Token,  Token>  {
readonly  IRule<Token,  TResult> rule;
public Not(IRule<Token,  TResult> rule)  {  this.rule  = rule;  }
public bool  TryParse(ISource<Token> source,  out Token result)  {
result  = default(Token);
if (!source.HasMore)
return false;
int originalIndex  = source.CurrentIndex;
TResult throwAwayResult;
bool  matches  = rule.TryParse(source,  out  throwAwayResult);
if (matches)
{
source.Move(originalIndex);
return false;
}
source.Move(originalIndex);
result  = source.Current;
source.Move(originalIndex  + 1);
return true;
}
}
Spot the bug!
Many (Once, Zero, and more times)
public class Many<Token,  TResult>  :  IRule<Token,  TResult[]>  {
readonly  IRule<Token,  TResult> rule;
readonly  bool  requireAtLeastOne;
public Many(IRule<Token,  TResult> rule,  bool requireAtLeastOne)  {  this.rule  = rule;  this.requireAtLeastOne  = requireAtLeastOne;  }
public bool  TryParse(ISource<Token> source,  out TResult[]  results)  {
List<TResult> buffer  = new List<TResult>();
while (source.HasMore)  {
int originalIndex  = source.CurrentIndex;
TResult result;
bool  matched  = rule.TryParse(source,  out  result);
if (!matched)  {
source.Move(originalIndex);
break;
}
buffer.Add(result);
}
if (requireAtLeastOne  && buffer.Count == 0)  {
results  = null;
return false;
}
results  = buffer.ToArray();
return true;
}
}
Map Result
public abstract class MapTo<Token,  TIn,  TOut>  :  IRule<Token,  TOut>  {
readonly  IRule<Token,  TIn> rule;
protected MapTo(IRule<Token,  TIn> rule)  {  this.rule  = rule;  }
protected abstract TOut Convert(TIn value);
public bool  TryParse(ISource<Token> source,  out TOut result)  {
result  = default(TOut);
int originalIndex  = source.CurrentIndex;
TIn resultIn;
if (!rule.TryParse(source,  out  resultIn))  {
source.Move(originalIndex);
return false;
}
result  = Convert(resultIn);
return true;
}
}
Map Result
public class JoinText :  MapTo<char,  char[],  string>  {
public JoinText(IRule<char,  char[]> rule)  :  base(rule)  {  }
protected override  string  Convert(char[]  value)  =>  new  string(value);
}
public class MapToInteger :  MapTo<char,  string,  int>  {
public MapToInteger(IRule<char,  string> rule)  :  base(rule)  {  }
protected override  int Convert(string value)  =>  int.Parse(value);
}
Putting the blocks together
var  quote  = new CharIs('"');
var  slash  = new CharIs('');
var  escapedQuote  = new MatchThenKeep<char,  char,  char>(slash,  quote);
var  escapedSlash  = new MatchThenKeep<char,  char,  char>(slash,  slash);
var  notQuote  = new Not<char,  char>(quote);
var  insideQuoteChar  = new FirstMatch<char,  char>(new[]  {
(IRule<char,  char>)escapedQuote,
escapedSlash,
notQuote
});
var  insideQuote  = new Many<char,  char>(insideQuoteChar,  false);
var  insideQuoteAsString  = new JoinText(insideQuote);
var  openQuote  = new MatchThenKeep<char,  char,  string>(quote,  
insideQuoteAsString);
var  fullQuote  = new MatchThenIgnore<char,  string,  char>(openQuote,  quote);
var  source  = new StringSource(raw);
string  asQuote;
if (fullQuote.TryParse(source,  out  asQuote))
return asQuote;
source.Move(0);
int asInteger;
if (digitsAsInt.TryParse(source,  out  asInteger))
return asInteger;
return null;
var  digit  = new CharIsDigit();
var  digits  = new Many<char,  char>(digit,  true);
var  digitsString  = new JoinText(digits);
var  digitsAsInt  = new MapToInteger(digitsString);
A Comparison
A Comparison
A Comparison
What an Improvement!
A Comparison (just the definition)
Room for Improvement
public abstract class MatchThen<Token,  TLeft,  TRight,  TOut>  :  IRule<Token,  TOut>  {
readonly  IRule<Token,  TLeft> leftRule;
readonly  IRule<Token,  TRight> rightRule;
protected abstract TOut Combine(TLeft leftResult,  TRight rightResult);
public MatchThen(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  {
this.leftRule  = leftRule;
this.rightRule  = rightRule;
}
public bool  TryParse(ISource<Token> source,  out TOut result)  {
int originalIndex  = source.CurrentIndex;
result  = default(TOut);
TLeft leftResult;
if (!leftRule.TryParse(source,  out  leftResult))  {
source.Move(originalIndex);
return false;
}
TRight rightResult;
if (!rightRule.TryParse(source,  out  rightResult))  {
source.Move(originalIndex);
return false;
}
result  = Combine(leftResult,  rightResult);
return true;
}
}
Out parameter :(
Managing the source’s index
Iteration 2.1
Immutability
An Immutable Source
public interface ISource<Token>  {
Token Current {  get;  }
bool  HasMore {  get;  }
int CurrentIndex {  get;  }
void Move(int index);
}
public interface ISource<Token>  {
Token Current {  get;  }
bool  HasMore {  get;  }
ISource<Token> Next();
}
An Immutable Source
public class StringSource :  ISource<char>  {
readonly  string  value;
int index;
public StringSource(string value)  {  
this.value  = value;  }
public char Current  => value[index];
public int CurrentIndex  => index;
public bool  HasMore  => index  < value.Length;
public void Move(int index)  =>  this.index  =  index;
}
public class StringSource :  ISource<char>  {
readonly  string  value;
readonly  int index;
public StringSource(string value,  int index =  0)  {  
this.value  = value;  this.index  = index;  }
public char Current  => value[index];
public bool  HasMore  => index  < value.Length;
public ISource<char> Next()  =>  
new  StringSource(value,  index +  1);
}
Ditch the Out
public class Result<Token,  TValue>  {
public bool  Success {  get;  }
public TValue Value {  get;  }
public string  Message {  get;  }
public ISource<Token> Next {  get;  }
public Result(bool success,  TValue value,  string message,  ISource<Token> next)  {
Success = success;
Value = value;
Message = message;
Next = next;
}
}
public interface IRule<Token,  TValue>  {
Result<Token,  TValue> TryParse(ISource<Token> source);
}
Char Matches...
public abstract class CharMatches :  IRule<char,  char>  {
protected abstract bool  IsCharMatch(char c);
public bool  TryParse(ISource<char> source,  out char result)  {
result  = default(char);
if (!source.HasMore)
return false;
if (!IsCharMatch(source.Current))
return false;
result  = source.Current;
source.Move(source.CurrentIndex + 1);
return true;
}
}
public abstract class CharMatches :  IRule<char,  char>  {
protected abstract bool  IsCharMatch(char c);
public Result<char,  char> TryParse(ISource<char> source)  {
if (!source.HasMore)
return new Result<char,  char>(false,  '0',  "Unexpected  EOF",  null);
if (!IsCharMatch(source.Current))
return new Result<char,  char>(false,  '0',  $"Unexpected  char:  {source.Current}",  null);
return new Result<char,  char>(true,  source.Current,  null,  source.Next());
}
}
These Don’t Change
public class CharIsDigit :  CharMatches  {
protected override  bool  IsCharMatch(char c)  =>  char.IsDigit(c);
}
public class CharIs :  CharMatches  {
readonly  char toMatch;
public CharIs(char toMatch)  {  this.toMatch  = toMatch;  }
protected override  bool  IsCharMatch(char c)  =>  c  ==  toMatch;
}
First Match
public class FirstMatch<Token,  TResult>  :  IRule<Token,  TResult>  {
readonly  IRule<Token,  TResult>[]  rules;
public FirstMatch(IRule<Token,  TResult>[]  rules)  {  this.rules  = rules;  }
public bool  TryParse(ISource<Token> source,  out TResult result)  {
foreach(var  rule  in  rules)  {
int originalIndex  = source.CurrentIndex;
if (rule.TryParse(source,  out  result))
return true;
source.Move(originalIndex);
}
result  = default(TResult);
return false;
}
}
public class FirstMatch<Token,  TResult>  :  IRule<Token,  TResult>  {
readonly  IRule<Token,  TResult>[]  rules;
public FirstMatch(IRule<Token,  TResult>[]  rules)  {  this.rules  = rules;  }
public Result<Token,  TResult> TryParse(ISource<Token> source)  {
foreach  (var  rule  in  rules)  {
var  result  = rule.TryParse(source);
if (result.Success)
return result;
}
return new Result<Token,  TResult>(false,  default(TResult),  "No  rule  matched",  null);
}
}
Match Then...
public bool  TryParse(ISource<Token> source,  out TOut result)  {
int originalIndex  = source.CurrentIndex;
result  = default(TOut);
TLeft leftResult;
if (!leftRule.TryParse(source,  out  leftResult))  {
source.Move(originalIndex);
return false;
}
TRight rightResult;
if (!rightRule.TryParse(source,  out  rightResult))  {
source.Move(originalIndex);
return false;
}
result  = Combine(leftResult,  rightResult);
return true;
}
public Result<Token,  TOut> TryParse(ISource<Token> source)  {
var  leftResult  = leftRule.TryParse(source);
if (!leftResult.Success)
return new Result<Token,  TOut>(false,  default(TOut),  leftResult.Message,  null);
var  rightResult  = rightRule.TryParse(leftResult.Next);
if (!rightResult.Success)
return new Result<Token,  TOut>(false,  default(TOut),  rightResult.Message,  null);
var  result  = Combine(leftResult.Value,  rightResult.Value);
return new Result<Token,  TOut>(true,  result,  null,  rightResult.Next);
}
Invert Rule (Not)
public class Not<Token,  TResult>  :  IRule<Token,  Token>  {
readonly  IRule<Token,  TResult> rule;
public Not(IRule<Token,  TResult> rule)  {  this.rule  = rule;  }
public bool  TryParse(ISource<Token> source,  out Token result)  {
result  = default(Token);
if (!source.HasMore)
return false;
int originalIndex  = source.CurrentIndex;
TResult throwAwayResult;
bool  matches  = rule.TryParse(source,  out  throwAwayResult);
if (matches)
{
source.Move(originalIndex);
return false;
}
source.Move(originalIndex);
result  = source.Current;
source.Move(originalIndex  + 1);
return true;
}
}
public class Not<Token,  TResult>  :  IRule<Token,  Token>  {
readonly  IRule<Token,  TResult> rule;
public Not(IRule<Token,  TResult> rule)  {  this.rule  = rule;  }
public Result<Token,  Token> TryParse(ISource<Token> source)  {
if (!source.HasMore)
return new Result<Token,  Token>(false,  default(Token),  "Unexpected  
EOF",  null);
var  result  = rule.TryParse(source);
if (result.Success)
return new Result<Token,  Token>(false,  default(Token),  "Unexpected  
match",  null);
return new Result<Token,  Token>(true,  source.Current,  null,  
source.Next());
}
}
Getting Better, but...
Still Room for Improvement
public class Result<Token,  TValue>  {
public bool  Success {  get;  }
public TValue Value {  get;  }
public string  Message {  get;  }
public ISource<Token> Next {  get;  }
public Result(bool success,  TValue value,  string message,  ISource<Token> next)  {
Success = success;
Value = value;
Message = message;
Next = next;
}
}
Only valid when Success = true
Only valid when Success = false
Iteration 2.2
Discriminated Unions and Pattern Matching (sorta)
Two States (Simple “Result” Example)
public interface IResult {  }
public class SuccessResult<TValue>  :  IResult  {
public TValue Value {  get;  }
public SuccessResult(TValue value)  {  Value = value;  }
}
public class ErrorResult :  IResult  {
public string  Message {  get;  }
public ErrorResult(string message)  {  Message = message;  }
}
Two States (The Matching)
IResult result  = ParseIt();
if (result  is  SuccessResult<string>)  {
var  success  = (SuccessResult<string>)result;
Console.WriteLine($"SUCCESS:  {success.Value}");
}  else if (result  is  ErrorResult)  {
var  error  = (ErrorResult)result;
Console.WriteLine($"ERR:  {error.Message}");
}
Pattern Matching(ish)
public interface IResult<TValue>  {
T  Match<T>(Func<SuccessResult<TValue>,  T> success,
Func<ErrorResult<TValue>,  T> error);
}
public class SuccessResult<TValue>  :  IResult<TValue>  {
public TValue Value {  get;  }
public SuccessResult(TValue value)  {  Value = value;  }
public T  Match<T>(Func<SuccessResult<TValue>,  T> success,
Func<ErrorResult<TValue>,  T> error)  =>  success(this);
}
public class ErrorResult<TValue>  :  IResult<TValue>
{
public string  Message {  get;  }
public ErrorResult(string message)  {  Message = message;  }
public T  Match<T>(Func<SuccessResult<TValue>,  T> success,
Func<ErrorResult<TValue>,  T> error)  =>  error(this);
}
Pattern Matching(ish)
IResult<string> result  = ParseIt();
string  message  = result.Match(
success  => $"SUCCESS:  ${success.Value}",
error  => $"ERR:  {error.Message}");
Console.WriteLine(message);
IResult result  = ParseIt();
if (result  is  SuccessResult<string>)  {
var  success  = (SuccessResult<string>)result;
Console.WriteLine($"SUCCESS:  {success.Value}");
}  else if (result  is  ErrorResult)  {
var  error  = (ErrorResult)result;
Console.WriteLine($"ERR:  {error.Message}");
}
The Match
Method
Forces us to handle all cases
Gives us an object with only valid
properties for that state
The New IResult
public interface IResult<Token,  TValue>  {
T  Match<T>(Func<FailResult<Token,  TValue>,  T> fail,
Func<SuccessResult<Token,  TValue>,  T> success);
}
public class FailResult<Token,  TValue>  :  IResult<Token,  TValue>  {
public string  Message {  get;  }
public FailResult(string message)  {  Message = message;  }
public T  Match<T>(Func<FailResult<Token,  TValue>,  T> fail,
Func<SuccessResult<Token,  TValue>,  T> success)  =>  fail(this);
}
public class SuccessResult<Token,  TValue>  :  IResult<Token,  TValue>  {
public TValue Value {  get;  }
public ISource<Token> Next {  get;  }
public SuccessResult(TValue value,  ISource<Token> next)  {  Value = value;  Next = next;  }
public T  Match<T>(Func<FailResult<Token,  TValue>,  T> fail,
Func<SuccessResult<Token,  TValue>,  T> success)  =>  success(this);
}
ISource also Represents Two States
public interface ISource<Token>  {
Token Current {  get;  }
bool  HasMore {  get;  }
ISource<Token> Next();
}
Only valid when HasMore = true
The New ISource
public interface ISource<Token>  {
T  Match<T>(Func<EmtySource<Token>,  T> empty,
Func<SourceWithMoreContent<Token>,  T> hasMore);
}
public class EmtySource<Token>  :  ISource<Token>  {
//  No  properties!    No  state!    Let's  just  make  it  singleton.
EmtySource()  {  }
public static readonly  EmtySource<Token> Instance  = new EmtySource<Token>();
public T  Match<T>(Func<EmtySource<Token>,  T> empty,
Func<SourceWithMoreContent<Token>,  T> hasMore)  =>  empty(this);
}
public class SourceWithMoreContent<Token>  :  ISource<Token>  {
readonly  Func<ISource<Token>> getNext;
public SourceWithMoreContent(Token current,  Func<ISource<Token>> getNext)  {  Current = current;  this.getNext  = getNext;  }
public Token Current {  get;  set;  }
public ISource<Token> Next()  =>  getNext();
public T  Match<T>(Func<EmtySource<Token>,  T> empty,
Func<SourceWithMoreContent<Token>,  T> hasMore)  =>  hasMore(this);
}
Make a String Source
public static class StringSource {
public static ISource<char> Create(string value,  int index =  0)  {
if (index  >= value.Length)
return EmtySource<char>.Instance;
return new SourceWithMoreContent<char>(value[index],  ()  => Create(value,  index  + 1));
}
}
public static ISource<char> Create(string  value,  int index  = 0)
=> index  >= value.Length
? (ISource<char>)EmtySource<char>.Instance
: new SourceWithMoreContent<char>(value[index],  ()  => Create(value,  index  + 1));
Char Matches... public abstract class CharMatches :  IRule<char,  char>  {
protected abstract bool  IsCharMatch(char c);
public Result<char,  char> TryParse(ISource<char> source)  {
if (!source.HasMore)
return new Result<char,  char>(false,  '0',  "Unexpected  EOF",  null);
if (!IsCharMatch(source.Current))
return new Result<char,  char>(false,  '0',  $"Unexpected  char:  {source.Current}",  null);
return new Result<char,  char>(true,  source.Current,  null,  source.Next());
}
}
public abstract class CharMatches :  IRule<char,  char>  {
protected abstract bool  IsCharMatch(char c);
public IResult<char,  char> TryParse(ISource<char> source)  {
var  result  = source.Match(
empty  => (IResult<char,  char>)new FailResult<char,  char>("Unexpected  EOF"),
hasMore  =>
{
if (!IsCharMatch(hasMore.Current))
return new FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}");
return new SuccessResult<char,  char>(hasMore.Current,  hasMore.Next());
});
return result;
}
}
public IResult<char,  char> TryParse(ISource<char> source)
=> source.Match(
empty  => new FailResult<char,  char>("Unexpected  EOF"),
hasMore  => IsCharMatch(hasMore.Current)
? new SuccessResult<char,  char>(hasMore.Current,  hasMore.Next())
: (IResult<char,  char>)new FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}")
);
Match Then...
public IResult<Token,  TOut> TryParse(ISource<Token> source)  {
var  leftResult  = leftRule.TryParse(source);
var  finalResult  = leftResult.Match(
leftFail  => new FailResult<Token,  TOut>(leftFail.Message),
leftSuccess  => {
var  rightResult  = rightRule.TryParse(leftSuccess.Next);
var  rightFinalResult  = rightResult.Match(
rightFail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(rightFail.Message),
rightSuccess  => {
var  finalValue  = Combine(leftSuccess.Value,  rightSuccess.Value);
return new SuccessResult<Token,  TOut>(finalValue,  rightSuccess.Next);
});
return rightFinalResult;
});
return finalResult;
}
public Result<Token,  TOut> TryParse(ISource<Token> source)  {
var  leftResult  = leftRule.TryParse(source);
if (!leftResult.Success)
return new Result<Token,  TOut>(false,  default(TOut),  leftResult.Message,  null);
var  rightResult  = rightRule.TryParse(leftResult.Next);
if (!rightResult.Success)
return new Result<Token,  TOut>(false,  default(TOut),  rightResult.Message,  null);
var  result  = Combine(leftResult.Value,  rightResult.Value);
return new Result<Token,  TOut>(true,  result,  null,  rightResult.Next);
}
public IResult<Token,  TOut> TryParse(ISource<Token> source)
=> leftRule.TryParse(source).Match(
leftFail  => new FailResult<Token,  TOut>(leftFail.Message),
leftSuccess  =>
rightRule.TryParse(leftSuccess.Next).Match(
rightFail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(rightFail.Message),
rightSuccess  => new SuccessResult<Token,  TOut>(Combine(leftSuccess.Value,  rightSuccess.Value),  
rightSuccess.Next)
)
);
Invert Rule (Not)
public Result<Token,  Token> TryParse(ISource<Token> source)  {
if (!source.HasMore)
return new Result<Token,  Token>(false,  default(Token),  "Unexpected  EOF",  null);
var  result  = rule.TryParse(source);
if (result.Success)
return new Result<Token,  Token>(false,  default(Token),  "Unexpected  match",  null);
return new Result<Token,  Token>(true,  source.Current,  null,  source.Next());
}
public IResult<Token,  Token> TryParse(ISource<Token> source)
=> source.Match(
empty  => new FailResult<Token,  Token>("Unexpected  EOF"),
current  => rule.TryParse(current).Match(
fail  => new SuccessResult<Token,  Token>(current.Current,  current.Next()),
success  => (IResult<Token,  Token>)new FailResult<Token,  Token>("Unexpected  match")
)
);
That’s nice but...
Let’s Be Honest
All these `new` objects are ugly.
var  quote  = new CharIs('"');
var  slash  = new CharIs('');
var  escapedQuote  = new MatchThenKeep<char,  char,  
char>(slash,  quote);
var  escapedSlash  = new MatchThenKeep<char,  char,  
char>(slash,  slash);
var  notQuote  = new Not<char,  char>(quote);
var  insideQuoteChar  = new FirstMatch<char,  char>(new[]  {
(IRule<char,  char>)escapedQuote,
escapedSlash,
notQuote
});
var  insideQuote  = new Many<char,  char>(insideQuoteChar,  
false);
var  insideQuoteAsString  = new JoinText(insideQuote);
var  openQuote  = new MatchThenKeep<char,  char,  
string>(quote,  insideQuoteAsString);
var  fullQuote  = new MatchThenIgnore<char,  string,  
char>(openQuote,  quote);
Also
Single method interfaces are lame*.
It’s effectively a delegate.
public interface IRule<Token,  TValue>  {
IResult<Token,  TValue> TryParse(ISource<Token> source);
}
*In  a  non-­scientific  poll  of  people  who  agree  with  me,  100%  of  
respondents  confirmed  this  statement.    Do  not  question  its  validity.
Iteration 3.0
Functions as First Class Citizens
A Rule is a Delegate is a Function
public interface IRule<Token,  TValue>  {
IResult<Token,  TValue> TryParse(ISource<Token> source);
}
public delegate  IResult<Token,  TValue> Rule<Token,  TValue>(ISource<Token> source);
Char Matches...
public abstract class CharMatches :  IRule<char,  char>  {
protected abstract bool  IsCharMatch(char c);
public IResult<char,  char> TryParse(ISource<char> source)
=>  source.Match(
empty =>  new FailResult<char,  char>("Unexpected EOF"),
hasMore  =>  IsCharMatch(hasMore.Current)
?  new  SuccessResult<char,  char>(hasMore.Current,  hasMore.Next())
:  (IResult<char,  char>)new  FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}")
);
}
public static class Rules {
public static Rule<char,  char> CharMatches(Func<char,  bool> isMatch)
=>  (source)  =>  source.Match(
empty =>  new FailResult<char,  char>("Unexpected EOF"),
hasMore  =>  isMatch(hasMore.Current)
?  new  SuccessResult<char,  char>(hasMore.Current,  hasMore.Next())
:  (IResult<char,  char>)new  FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}")
);
}
public static Rule<char,  char> CharIsDigit()  => CharMatches(char.IsDigit);
public static Rule<char,  char> CharIs(char c)  => CharMatches(x  => x  == c);
Then (Keep|Ignore)
public static Rule<Token,  TOut> MatchThen<Token,  TLeft,  TRight,  TOut>(this Rule<Token,  TLeft> leftRule,  Rule<Token,  
TRight> rightRule,  Func<TLeft,  TRight,  TOut> convert)
=> (source)  => leftRule(source).Match(
leftFail  => new FailResult<Token,  TOut>(leftFail.Message),
leftSuccess  =>
rightRule(leftSuccess.Next).Match(
rightFail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(rightFail.Message),
rightSuccess  => new SuccessResult<Token,  TOut>(convert(leftSuccess.Value,  rightSuccess.Value),  
rightSuccess.Next)
)
);
public static Rule<Token,  TRight> MatchThenKeep<Token,  TLeft,  TRight>(this Rule<Token,  TLeft> leftRule,  Rule<Token,  
TRight> rightRule)
=> MatchThen(leftRule,  rightRule,  (left,  right)  => right);
public static Rule<Token,  TLeft> MatchThenIgnore<Token,  TLeft,  TRight>(this Rule<Token,  TLeft> leftRule,  Rule<Token,  
TRight> rightRule)
=> MatchThen(leftRule,  rightRule,  (left,  right)  => left);
Not, MapTo, JoinText, MapToInteger
public static Rule<Token,  Token> Not<Token,  TResult>(this Rule<Token,  TResult> rule)
=> (source)  => source.Match(
empty  => new FailResult<Token,  Token>("Unexpected  EOF"),
current  => rule(current).Match(
fail  => new SuccessResult<Token,  Token>(current.Current,  current.Next()),
success  => (IResult<Token,  Token>)new FailResult<Token,  Token>("Unexpected  match")
)
);
public static Rule<Token,  TOut> MapTo<Token,  TIn,  TOut>(this Rule<Token,  TIn> rule,  Func<TIn,  TOut> convert)
=> (source)  => rule(source).Match(
fail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(fail.Message),
success  => new SuccessResult<Token,  TOut>(convert(success.Value),  success.Next)
);
public static Rule<char,  string> JoinText(this Rule<char,  char[]> rule)
=> MapTo(rule,  (x)  => new string(x));
public static Rule<char,  int> MapToInteger(this Rule<char,  string> rule)
=> MapTo(rule,  (x)  => int.Parse(x));
Example Usage
var  quote  = Rules.CharIs('"');
var  slash  = Rules.CharIs('');
var  escapedQuote  =  Rules.MatchThenKeep(slash,  quote);
var  escapedSlash  = slash.MatchThenKeep(slash);
The Original 2.0 Definition
var  quote  = new CharIs('"');
var  slash  = new CharIs('');
var  escapedQuote  = new MatchThenKeep<char,  char,  char>(slash,  quote);
var  escapedSlash  = new MatchThenKeep<char,  char,  char>(slash,  slash);
var  notQuote  = new Not<char,  char>(quote);
var  insideQuoteChar  = new FirstMatch<char,  char>(new[]  {
(IRule<char,  char>)escapedQuote,
escapedSlash,
notQuote
});
var  insideQuote  = new Many<char,  char>(insideQuoteChar,  false);
var  insideQuoteAsString  = new JoinText(insideQuote);
var  openQuote  = new MatchThenKeep<char,  char,  string>(quote,  
insideQuoteAsString);
var  fullQuote  = new MatchThenIgnore<char,  string,  char>(openQuote,  quote);
var  source  = new StringSource(raw);
string  asQuote;
if (fullQuote.TryParse(source,  out  asQuote))
return asQuote;
source.Move(0);
int asInteger;
if (digitsAsInt.TryParse(source,  out  asInteger))
return asInteger;
return null;
var  digit  = new CharIsDigit();
var  digits  = new Many<char,  char>(digit,  true);
var  digitsString  = new JoinText(digits);
var  digitsAsInt  = new MapToInteger(digitsString);
The Updated 3.0 Definition
var  quote  = Rules.CharIs('"');
var  slash  = Rules.CharIs('');
var  escapedQuote  = slash.MatchThenKeep(quote);
var  escapedSlash  = slash.MatchThenKeep(slash);
var  notQuote  = quote.Not();
var  fullQuote  = quote
.MatchThenKeep(
Rules.FirstMatch(
escapedQuote,
escapedSlash,
notQuote
).Many().JoinText()
)
.MatchThenIgnore(quote);
var  finalResult  = Rules.FirstMatch(
fullQuote.MapTo(x  => (object)x),
digit.MapTo(x  => (object)x)
);
var  source  = StringSource.Create(raw);
return finalResult(source).Match(
fail  => null,
success  => success.Value
);
var  integer  = Rules.CharIsDigit()
.Many(true)
.JoinText()
.MapToInteger();
A Comparison V1 -> V3
A Comparison V1 -> V3
A Comparison V1 -> V3 (Just Definition)
Looks Great!
My co-workers are going to kill me
Is it a good idea?
public static Rule<Token,  Token> Not<Token,  TResult>(this Rule<Token,  TResult> rule)
=> (source)  => source.Match(
empty  => new FailResult<Token,  Token>("Unexpected  EOF"),
current  => rule(current).Match(
fail  => new SuccessResult<Token,  Token>(current.Current,  current.Next()),
success  => (IResult<Token,  Token>)new FailResult<Token,  Token>("Unexpected  match")
)
);
public static Rule<Token,  TOut> MapTo<Token,  TIn,  TOut>(this Rule<Token,  TIn> rule,  Func<TIn,  TOut> convert)
=> (source)  => rule(source).Match(
fail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(fail.Message),
success  => new SuccessResult<Token,  TOut>(convert(success.Value),  success.Next)
);
public static Rule<char,  string> JoinText(this Rule<char,  char[]> rule)
=> MapTo(rule,  (x)  => new string(x));
public static Rule<char,  int> MapToInteger(this Rule<char,  string> rule)
=> MapTo(rule,  (x)  => int.Parse(x));
Limitations
“At Zombocom, the only limit…
is yourself.”
1. Makes a LOT of short-lived
objects (ISources, IResults).
2. As written currently, you will end
up with the entire thing in
memory.
3. Visual Studio’s Intellisense
struggles with nested lambdas.
4. Frequently requires casts to solve
type inference problems.
5. It’s not very C#.
Let’s Review
Iterations
Iteration 1.0: Procedural
Iteration 2.0: Making Compositional
with OOP
Iteration 2.1: Immutability
Iteration 2.2: Discriminated Unions and
Pattern Matching
Iteration 3.0: Functions as First Class
Citizens
That’s All
Thanks for coming and staying awake!

More Related Content

What's hot

String in python use of split method
String in python use of split methodString in python use of split method
String in python use of split method
vikram mahendra
 
The Swift Compiler and Standard Library
The Swift Compiler and Standard LibraryThe Swift Compiler and Standard Library
The Swift Compiler and Standard Library
Santosh Rajan
 
Learn python in 20 minutes
Learn python in 20 minutesLearn python in 20 minutes
Learn python in 20 minutes
Sidharth Nadhan
 
Logic programming a ruby perspective
Logic programming a ruby perspectiveLogic programming a ruby perspective
Logic programming a ruby perspective
Norman Richards
 
Coding in Kotlin with Arrow NIDC 2018
Coding in Kotlin with Arrow NIDC 2018Coding in Kotlin with Arrow NIDC 2018
Coding in Kotlin with Arrow NIDC 2018
Garth Gilmour
 
The Arrow Library in Kotlin
The Arrow Library in KotlinThe Arrow Library in Kotlin
The Arrow Library in Kotlin
Garth Gilmour
 
Python and sysadmin I
Python and sysadmin IPython and sysadmin I
Python and sysadmin I
Guixing Bai
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
José Paumard
 
Python 101++: Let's Get Down to Business!
Python 101++: Let's Get Down to Business!Python 101++: Let's Get Down to Business!
Python 101++: Let's Get Down to Business!
Paige Bailey
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
José Paumard
 
An Intro to Python in 30 minutes
An Intro to Python in 30 minutesAn Intro to Python in 30 minutes
An Intro to Python in 30 minutes
Sumit Raj
 
Learn python - for beginners - part-2
Learn python - for beginners - part-2Learn python - for beginners - part-2
Learn python - for beginners - part-2
RajKumar Rampelli
 
FUNDAMENTALS OF PYTHON LANGUAGE
 FUNDAMENTALS OF PYTHON LANGUAGE  FUNDAMENTALS OF PYTHON LANGUAGE
FUNDAMENTALS OF PYTHON LANGUAGE
Saraswathi Murugan
 
Strings in python
Strings in pythonStrings in python
Strings in python
Prabhakaran V M
 
Python language data types
Python language data typesPython language data types
Python language data types
Hoang Nguyen
 
Introduction to Python - Part Three
Introduction to Python - Part ThreeIntroduction to Python - Part Three
Introduction to Python - Part Three
amiable_indian
 
Free your lambdas
Free your lambdasFree your lambdas
Free your lambdas
José Paumard
 
Introduction to advanced python
Introduction to advanced pythonIntroduction to advanced python
Introduction to advanced python
Charles-Axel Dein
 

What's hot (20)

String in python use of split method
String in python use of split methodString in python use of split method
String in python use of split method
 
The Swift Compiler and Standard Library
The Swift Compiler and Standard LibraryThe Swift Compiler and Standard Library
The Swift Compiler and Standard Library
 
Learn python in 20 minutes
Learn python in 20 minutesLearn python in 20 minutes
Learn python in 20 minutes
 
Logic programming a ruby perspective
Logic programming a ruby perspectiveLogic programming a ruby perspective
Logic programming a ruby perspective
 
Coding in Kotlin with Arrow NIDC 2018
Coding in Kotlin with Arrow NIDC 2018Coding in Kotlin with Arrow NIDC 2018
Coding in Kotlin with Arrow NIDC 2018
 
The Arrow Library in Kotlin
The Arrow Library in KotlinThe Arrow Library in Kotlin
The Arrow Library in Kotlin
 
Python and sysadmin I
Python and sysadmin IPython and sysadmin I
Python and sysadmin I
 
python.ppt
python.pptpython.ppt
python.ppt
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
 
Python 101++: Let's Get Down to Business!
Python 101++: Let's Get Down to Business!Python 101++: Let's Get Down to Business!
Python 101++: Let's Get Down to Business!
 
The Sincerest Form of Flattery
The Sincerest Form of FlatteryThe Sincerest Form of Flattery
The Sincerest Form of Flattery
 
An Intro to Python in 30 minutes
An Intro to Python in 30 minutesAn Intro to Python in 30 minutes
An Intro to Python in 30 minutes
 
Learn python - for beginners - part-2
Learn python - for beginners - part-2Learn python - for beginners - part-2
Learn python - for beginners - part-2
 
FUNDAMENTALS OF PYTHON LANGUAGE
 FUNDAMENTALS OF PYTHON LANGUAGE  FUNDAMENTALS OF PYTHON LANGUAGE
FUNDAMENTALS OF PYTHON LANGUAGE
 
Python
PythonPython
Python
 
Strings in python
Strings in pythonStrings in python
Strings in python
 
Python language data types
Python language data typesPython language data types
Python language data types
 
Introduction to Python - Part Three
Introduction to Python - Part ThreeIntroduction to Python - Part Three
Introduction to Python - Part Three
 
Free your lambdas
Free your lambdasFree your lambdas
Free your lambdas
 
Introduction to advanced python
Introduction to advanced pythonIntroduction to advanced python
Introduction to advanced python
 

Viewers also liked

Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...
Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...
Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...
Blend Interactive
 
Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...
Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...
Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...
Blend Interactive
 
The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...
The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...
The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...
Blend Interactive
 
“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...
“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...
“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...
Blend Interactive
 
Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...
Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...
Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...
Blend Interactive
 
Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...
Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...
Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...
Blend Interactive
 
"The Self-Directed Strategist: Building a Practice and Managing Organizationa...
"The Self-Directed Strategist: Building a Practice and Managing Organizationa..."The Self-Directed Strategist: Building a Practice and Managing Organizationa...
"The Self-Directed Strategist: Building a Practice and Managing Organizationa...
Blend Interactive
 
“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...
“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...
“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...
Blend Interactive
 
Object Oriented Programming with Java
Object Oriented Programming with JavaObject Oriented Programming with Java
Object Oriented Programming with JavaJussi Pohjolainen
 
Java Basics for selenium
Java Basics for seleniumJava Basics for selenium
Java Basics for selenium
apoorvams
 

Viewers also liked (11)

C# concepts
C# conceptsC# concepts
C# concepts
 
Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...
Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...
Busting the Field of Dreams Theory: Making Content Meaningful, Useful, and Fi...
 
Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...
Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...
Content Heavy Lifting: How to Recycle (and Upcycle) Your Content Over and Ove...
 
The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...
The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...
The Lone Ranger: Managing the Ups and Downs of One-Person Offices and Small T...
 
“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...
“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...
“The Five Meetings You Meet in Web Design” by Kevin Hoffman (Now What? Confer...
 
Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...
Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...
Next Level Collaboration: The Future of Content and Design by Rebekah Cancino...
 
Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...
Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...
Reducing Digital Clutter: How to Clean Up the Back of Your House by Matt Groc...
 
"The Self-Directed Strategist: Building a Practice and Managing Organizationa...
"The Self-Directed Strategist: Building a Practice and Managing Organizationa..."The Self-Directed Strategist: Building a Practice and Managing Organizationa...
"The Self-Directed Strategist: Building a Practice and Managing Organizationa...
 
“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...
“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...
“Writing for Your Audience — The Message, the Words, the Plan” – Business Sen...
 
Object Oriented Programming with Java
Object Oriented Programming with JavaObject Oriented Programming with Java
Object Oriented Programming with Java
 
Java Basics for selenium
Java Basics for seleniumJava Basics for selenium
Java Basics for selenium
 

Similar to Functional concepts in C#

Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7
Paulo Morgado
 
What's New In C# 7
What's New In C# 7What's New In C# 7
What's New In C# 7
Paulo Morgado
 
Poly-paradigm Java
Poly-paradigm JavaPoly-paradigm Java
Poly-paradigm Java
Pavel Tcholakov
 
Clone Refactoring with Lambda Expressions
Clone Refactoring with Lambda ExpressionsClone Refactoring with Lambda Expressions
Clone Refactoring with Lambda Expressions
Nikolaos Tsantalis
 
devLink - What's New in C# 4?
devLink - What's New in C# 4?devLink - What's New in C# 4?
devLink - What's New in C# 4?
Kevin Pilch
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607
Kevin Hazzard
 
Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#
Mark Needham
 
Intel JIT Talk
Intel JIT TalkIntel JIT Talk
Intel JIT Talkiamdvander
 
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
tdc-globalcode
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
Abbas Raza
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
Prashant Kalkar
 
To Infinity & Beyond: Protocols & sequences in Node - Part 2
To Infinity & Beyond: Protocols & sequences in Node - Part 2To Infinity & Beyond: Protocols & sequences in Node - Part 2
To Infinity & Beyond: Protocols & sequences in Node - Part 2Bahul Neel Upadhyaya
 
core java
 core java core java
core java
dssreenath
 
Lambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive CodeLambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive Code
Ian Robertson
 
Python basic
Python basicPython basic
Python basic
Saifuddin Kaijar
 
Impala: A Modern, Open-Source SQL Engine for Hadoop
Impala: A Modern, Open-Source SQL Engine for HadoopImpala: A Modern, Open-Source SQL Engine for Hadoop
Impala: A Modern, Open-Source SQL Engine for Hadoop
All Things Open
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
HamletDRC
 

Similar to Functional concepts in C# (20)

Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7Tuga IT 2017 - What's new in C# 7
Tuga IT 2017 - What's new in C# 7
 
What's New In C# 7
What's New In C# 7What's New In C# 7
What's New In C# 7
 
Poly-paradigm Java
Poly-paradigm JavaPoly-paradigm Java
Poly-paradigm Java
 
Clone Refactoring with Lambda Expressions
Clone Refactoring with Lambda ExpressionsClone Refactoring with Lambda Expressions
Clone Refactoring with Lambda Expressions
 
devLink - What's New in C# 4?
devLink - What's New in C# 4?devLink - What's New in C# 4?
devLink - What's New in C# 4?
 
C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607C# 6 and 7 and Futures 20180607
C# 6 and 7 and Futures 20180607
 
Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#Mixing functional and object oriented approaches to programming in C#
Mixing functional and object oriented approaches to programming in C#
 
Intel JIT Talk
Intel JIT TalkIntel JIT Talk
Intel JIT Talk
 
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
TDC2016POA | Trilha .NET - C# como você nunca viu: conceitos avançados de pro...
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
To Infinity & Beyond: Protocols & sequences in Node - Part 2
To Infinity & Beyond: Protocols & sequences in Node - Part 2To Infinity & Beyond: Protocols & sequences in Node - Part 2
To Infinity & Beyond: Protocols & sequences in Node - Part 2
 
core java
 core java core java
core java
 
C tutorial
C tutorialC tutorial
C tutorial
 
C tutorial
C tutorialC tutorial
C tutorial
 
C tutorial
C tutorialC tutorial
C tutorial
 
Lambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive CodeLambda Chops - Recipes for Simpler, More Expressive Code
Lambda Chops - Recipes for Simpler, More Expressive Code
 
Python basic
Python basicPython basic
Python basic
 
Impala: A Modern, Open-Source SQL Engine for Hadoop
Impala: A Modern, Open-Source SQL Engine for HadoopImpala: A Modern, Open-Source SQL Engine for Hadoop
Impala: A Modern, Open-Source SQL Engine for Hadoop
 
Ast transformations
Ast transformationsAst transformations
Ast transformations
 

More from Blend Interactive

"The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ...
"The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ..."The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ...
"The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ...
Blend Interactive
 
"The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ...
"The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ..."The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ...
"The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ...
Blend Interactive
 
"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017
"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017
"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017
Blend Interactive
 
"Never Knowing Enough: dealing with the self doubt that hinders your success....
"Never Knowing Enough: dealing with the self doubt that hinders your success...."Never Knowing Enough: dealing with the self doubt that hinders your success....
"Never Knowing Enough: dealing with the self doubt that hinders your success....
Blend Interactive
 
"Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con..."Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con...
Blend Interactive
 
"Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con..."Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con...
Blend Interactive
 
Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...
Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...
Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...
Blend Interactive
 
Content Measurement and Analytics: Making Positive Change on the Web by Rick ...
Content Measurement and Analytics: Making Positive Change on the Web by Rick ...Content Measurement and Analytics: Making Positive Change on the Web by Rick ...
Content Measurement and Analytics: Making Positive Change on the Web by Rick ...
Blend Interactive
 
“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...
“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...
“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...
Blend Interactive
 
"Adaptive Content, Context, and Controversy
"Adaptive Content, Context, and Controversy"Adaptive Content, Context, and Controversy
"Adaptive Content, Context, and Controversy
Blend Interactive
 
"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017
"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017
"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017
Blend Interactive
 
“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017
“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017
“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017
Blend Interactive
 
“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017
“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017
“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017
Blend Interactive
 
Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...
Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...
Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...
Blend Interactive
 
Content Design for Mobile Devices - Now What? Conference 2017
Content Design for Mobile Devices - Now What? Conference 2017Content Design for Mobile Devices - Now What? Conference 2017
Content Design for Mobile Devices - Now What? Conference 2017
Blend Interactive
 
"Making Things Real: Taking content strategy from abstract to functional" - M...
"Making Things Real: Taking content strategy from abstract to functional" - M..."Making Things Real: Taking content strategy from abstract to functional" - M...
"Making Things Real: Taking content strategy from abstract to functional" - M...
Blend Interactive
 
"Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co...
"Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co..."Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co...
"Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co...
Blend Interactive
 
Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...
Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...
Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...
Blend Interactive
 
Living With Agile by Karl Fast (Now What? Conference 2015)
Living With Agile by Karl Fast (Now What? Conference 2015)Living With Agile by Karl Fast (Now What? Conference 2015)
Living With Agile by Karl Fast (Now What? Conference 2015)
Blend Interactive
 
Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...
Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...
Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...
Blend Interactive
 

More from Blend Interactive (20)

"The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ...
"The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ..."The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ...
"The Accessible Editor Workshop" by Corey Vilhauer, from Now What? Workshops ...
 
"The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ...
"The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ..."The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ...
"The Accessible Editor" by Corey Vilhauer, from DrupalCon 2018 in Nashville, ...
 
"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017
"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017
"Click to Continue" by Sam Otis, from Content+Design Meetup, Oct. 4, 2017
 
"Never Knowing Enough: dealing with the self doubt that hinders your success....
"Never Knowing Enough: dealing with the self doubt that hinders your success...."Never Knowing Enough: dealing with the self doubt that hinders your success....
"Never Knowing Enough: dealing with the self doubt that hinders your success....
 
"Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con..."Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con...
 
"Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con..."Making things real: Content strategy for realistic content management" - Con...
"Making things real: Content strategy for realistic content management" - Con...
 
Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...
Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...
Getting Started With User-Centered Content by Emileigh Barnes & Kate Garklavs...
 
Content Measurement and Analytics: Making Positive Change on the Web by Rick ...
Content Measurement and Analytics: Making Positive Change on the Web by Rick ...Content Measurement and Analytics: Making Positive Change on the Web by Rick ...
Content Measurement and Analytics: Making Positive Change on the Web by Rick ...
 
“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...
“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...
“How Silos Learn: Working in the Idea Factory” by Amanda Costello - Now What?...
 
"Adaptive Content, Context, and Controversy
"Adaptive Content, Context, and Controversy"Adaptive Content, Context, and Controversy
"Adaptive Content, Context, and Controversy
 
"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017
"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017
"Empathy Behind the Algorithms" by Chris Corak - Now What? Conference 2017
 
“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017
“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017
“The Beauty of Brevity” by Ravi Jain - Now What? Conference 2017
 
“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017
“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017
“Why Content Projects Fail” by Deane Barker - Now What? Conference 2017
 
Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...
Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...
Not Perfect, "Always Better: A Story of Inclusion" by Derek Featherstone - No...
 
Content Design for Mobile Devices - Now What? Conference 2017
Content Design for Mobile Devices - Now What? Conference 2017Content Design for Mobile Devices - Now What? Conference 2017
Content Design for Mobile Devices - Now What? Conference 2017
 
"Making Things Real: Taking content strategy from abstract to functional" - M...
"Making Things Real: Taking content strategy from abstract to functional" - M..."Making Things Real: Taking content strategy from abstract to functional" - M...
"Making Things Real: Taking content strategy from abstract to functional" - M...
 
"Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co...
"Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co..."Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co...
"Small CS: A Shoestring Approach to Content Strategy" by Corey Vilhauer at Co...
 
Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...
Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...
Introducing the Blend Web Operations Framework by Deane Barker (Now What? Con...
 
Living With Agile by Karl Fast (Now What? Conference 2015)
Living With Agile by Karl Fast (Now What? Conference 2015)Living With Agile by Karl Fast (Now What? Conference 2015)
Living With Agile by Karl Fast (Now What? Conference 2015)
 
Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...
Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...
Integrating Accessibility: Planning Content for Everyone by Eileen Webb (Now ...
 

Recently uploaded

From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
ControlCase
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
Ana-Maria Mihalceanu
 

Recently uploaded (20)

From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
PCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase TeamPCI PIN Basics Webinar from the Controlcase Team
PCI PIN Basics Webinar from the Controlcase Team
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
Monitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR EventsMonitoring Java Application Security with JDK Tools and JFR Events
Monitoring Java Application Security with JDK Tools and JFR Events
 

Functional concepts in C#

  • 1. Functional Concepts in C# Or “Who the F# Wrote This?” https://github.com/mrdrbob/sd-code-camp-2016
  • 4. What this talk is A gentle introduction to functional paradigms using a language you may already be familiar with. A comparison between OOP and functional styles A discussion on language expectations
  • 5. What this talk isn’t “OOP is dead!” “Functional all the things!” “All code should look exactly like this!” (Spoiler: it probably shouldn’t)
  • 6. Who I am Bob Davidson C# / Web Developer 11 years Blend Interactive A guy who is generally interested in and learning about functional programming concepts https://github.com/mrdrbob
  • 7. Who I am Not A functional programming expert who says things like: “All told, a monad in X is just a monoid in the category of endofunctors of X, with product × replaced by composition of endofunctors and unit set by the identity endofunctor.” -Saunders Mac Lane
  • 8. Let’s Build a Parser! A highly simplified JSON-like syntax for strings and integers.
  • 10. Strings Starts & ends with double quote. Quotes can be escaped with slash. Slash can be escaped with slash. Can be empty.
  • 12. The IParser<TValue> Interface public interface IParser<TValue>  { bool  TryParse(string raw,  out TValue value); }
  • 13. IntegerParser public class IntegerParser :  IParser<int>  { public bool  TryParse(string raw,  out int value)  { value  = 0; int x  = 0; List<char> buffer  = new List<char>(); while (x  < raw.Length && char.IsDigit(raw[x]))  { buffer.Add(raw[x]); x  += 1; } if (x  == 0) return false; //  Deal  with  it. value  = int.Parse(new string(buffer.ToArray())); return true; } }
  • 14. IntegerParser public class IntegerParser :  IParser<int>  { public bool  TryParse(string raw,  out int value)  { value  = 0; int x  = 0; List<char> buffer  = new List<char>(); while (x  < raw.Length && char.IsDigit(raw[x]))  { buffer.Add(raw[x]); x  += 1; } if (x  == 0) return false; value  = int.Parse(new string(buffer.ToArray())); return true; } }
  • 15. StringParser public class StringParser :  IParser<string>  { public bool  TryParse(string raw,  out string value)  { value  = null; int x  = 0; if (x  == raw.Length || raw[x]  != '"') return false; x  += 1; List<char> buffer  = new List<char>(); while (x  < raw.Length && raw[x]  != '"')  { if (raw[x]  == '')  { x  += 1; if (x  == raw.Length) return false; if (raw[x]  == '') buffer.Add(raw[x]); else if (raw[x]  == '"') buffer.Add(raw[x]); else return false; }  else { buffer.Add(raw[x]); } x  += 1; } if (x  == raw.Length) return false; x  += 1; value  = new string(buffer.ToArray()); return true; } }
  • 16. Possible Issues public class StringParser :  IParser<string>  { public bool  TryParse(string raw,  out string value)  { value  = null; int x  = 0; if (x  == raw.Length || raw[x]  != '"') return false; x  += 1; List<char> buffer  = new List<char>(); while (x  < raw.Length && raw[x]  != '"')  { if (raw[x]  == '')  { x  += 1; if (x  == raw.Length) return false; if (raw[x]  == '') buffer.Add(raw[x]); else if (raw[x]  == '"') buffer.Add(raw[x]); else return false; }  else { buffer.Add(raw[x]); } x  += 1; } if (x  == raw.Length) return false; x  += 1; value  = new string(buffer.ToArray()); return true; } } Repeated checks against running out of input Easily missed logic for moving input forward No way to see how much input was consumed / how much is left Hard to understand at a glance what is happening public class IntegerParser :  IParser<int>  { public bool  TryParse(string raw,  out int value)  { value  = 0; int x  = 0; List<char> buffer  = new List<char>(); while (x  < raw.Length && char.IsDigit(raw[x]))  { buffer.Add(raw[x]); x  += 1; } if (x  == 0) return false; //  Deal  with  it. value  = int.Parse(new string(buffer.ToArray())); return true; } }
  • 17. Rethinking the Parser Make a little more generic / reusable Break the process down into a series of rules which can be composed to make new parsers from existing parsers Build a framework that doesn’t rely on strings, but rather a stream of tokens
  • 20. One or More Times A Parser Built on Rules (Integer Parser) [0-9]
  • 21. Ignore Latter Keep Latter Zero or More Times Any of these NotKeep Latter A Parser Built on Rules (String Parser) “ “ Keep Latter Any of these “ “
  • 22. A Set of Rules Match Quote Match Slash Match Digit Match Then Keep Match Then Ignore Match Any Match Zero or More Times Match One or More Times Not
  • 23. Rethinking the Source Handle tokens other than chars (such as byte streams, pre-lexed tokens, etc) Need the ability to continue parsing after a success Need the ability to reset after a failure
  • 24. Rethinking the Source public interface ISource<Token>  { Token Current {  get;  } bool  HasMore {  get;  } int CurrentIndex {  get;  } void Move(int index); } public class StringSource :  ISource<char>  { readonly  string  value; int index; public StringSource(string value)  {  this.value  = value;  } public char Current  => value[index]; public int CurrentIndex  => index; public bool  HasMore  => index  < value.Length; public void Move(int index)  =>  this.index  =  index; }
  • 25. Creating a Rule public interface IRule<Token,  TResult>  { bool  TryParse(ISource<Token> source,  out TResult result); }
  • 26. Char Matches... public class CharIsQuote :  IRule<char,  char>  { public bool  TryParse(ISource<char> source,  out char result)  { result  = default(char); if (!source.HasMore) return false; if (source.Current != '"') return false; result  = source.Current; source.Move(source.CurrentIndex + 1); return true; } } public class CharIs :  IRule<char,  char>  { readonly  char toMatch; public CharIs(char toMatch)  {  this.toMatch  = toMatch;  } public bool  TryParse(ISource<char> source,  out char result)  { result  = default(char); if (!source.HasMore) return false; if (source.Current != toMatch) return false; result  = source.Current; source.Move(source.CurrentIndex + 1); return true; } }
  • 27. Char Matches... public abstract class CharMatches :  IRule<char,  char>  { protected abstract bool  IsCharMatch(char c); public bool  TryParse(ISource<char> source,  out char result)  { result  = default(char); if (!source.HasMore) return false; if (!IsCharMatch(source.Current)) return false; result  = source.Current; source.Move(source.CurrentIndex + 1); return true; } } public class CharIsDigit :  CharMatches  { protected override  bool  IsCharMatch(char c)  =>  char.IsDigit(c); } public class CharIs :  CharMatches  { readonly  char toMatch; public CharIs(char toMatch)  {  this.toMatch  = toMatch;  } protected override  bool  IsCharMatch(char c)  =>  c  ==  toMatch; }
  • 28. First Match (or Any) public class FirstMatch<Token,  TResult>  :  IRule<Token,  TResult>  { readonly  IRule<Token,  TResult>[]  rules; public FirstMatch(IRule<Token,  TResult>[]  rules)  {  this.rules  = rules;  } public bool  TryParse(ISource<Token> source,  out TResult result)  { foreach(var  rule  in  rules)  { int originalIndex  = source.CurrentIndex; if (rule.TryParse(source,  out  result)) return true; source.Move(originalIndex); } result  = default(TResult); return false; } }
  • 29. Match Then... public abstract class MatchThen<Token,  TLeft,  TRight,  TOut>  :  IRule<Token,  TOut>  { readonly  IRule<Token,  TLeft> leftRule; readonly  IRule<Token,  TRight> rightRule; protected abstract TOut Combine(TLeft leftResult,  TRight rightResult); public MatchThen(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  { this.leftRule  = leftRule; this.rightRule  = rightRule; } public bool  TryParse(ISource<Token> source,  out TOut result)  { int originalIndex  = source.CurrentIndex; result  = default(TOut); TLeft leftResult; if (!leftRule.TryParse(source,  out  leftResult))  { source.Move(originalIndex); return false; } TRight rightResult; if (!rightRule.TryParse(source,  out  rightResult))  { source.Move(originalIndex); return false; } result  = Combine(leftResult,  rightResult); return true; } }
  • 30. Match Then... public class MatchThenKeep<Token,  TLeft,  TRight>  :  MatchThen<Token,  TLeft,  TRight,  TRight>  { public MatchThenKeep(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  :  base(leftRule,  rightRule)  {  } protected override  TRight Combine(TLeft leftResult,  TRight rightResult)  =>  rightResult; } public class MatchThenIgnore<Token,  TLeft,  TRight>  :  MatchThen<Token,  TLeft,  TRight,  TLeft>  { public MatchThenIgnore(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  :  base(leftRule,  rightRule)  {  } protected override  TLeft Combine(TLeft leftResult,  TRight rightResult)  =>  leftResult; }
  • 31. Invert Rule (Not) public class Not<Token,  TResult>  :  IRule<Token,  Token>  { readonly  IRule<Token,  TResult> rule; public Not(IRule<Token,  TResult> rule)  {  this.rule  = rule;  } public bool  TryParse(ISource<Token> source,  out Token result)  { result  = default(Token); if (!source.HasMore) return false; int originalIndex  = source.CurrentIndex; TResult throwAwayResult; bool  matches  = rule.TryParse(source,  out  throwAwayResult); if (matches) { source.Move(originalIndex); return false; } source.Move(originalIndex); result  = source.Current; source.Move(originalIndex  + 1); return true; } } Spot the bug!
  • 32. Many (Once, Zero, and more times) public class Many<Token,  TResult>  :  IRule<Token,  TResult[]>  { readonly  IRule<Token,  TResult> rule; readonly  bool  requireAtLeastOne; public Many(IRule<Token,  TResult> rule,  bool requireAtLeastOne)  {  this.rule  = rule;  this.requireAtLeastOne  = requireAtLeastOne;  } public bool  TryParse(ISource<Token> source,  out TResult[]  results)  { List<TResult> buffer  = new List<TResult>(); while (source.HasMore)  { int originalIndex  = source.CurrentIndex; TResult result; bool  matched  = rule.TryParse(source,  out  result); if (!matched)  { source.Move(originalIndex); break; } buffer.Add(result); } if (requireAtLeastOne  && buffer.Count == 0)  { results  = null; return false; } results  = buffer.ToArray(); return true; } }
  • 33. Map Result public abstract class MapTo<Token,  TIn,  TOut>  :  IRule<Token,  TOut>  { readonly  IRule<Token,  TIn> rule; protected MapTo(IRule<Token,  TIn> rule)  {  this.rule  = rule;  } protected abstract TOut Convert(TIn value); public bool  TryParse(ISource<Token> source,  out TOut result)  { result  = default(TOut); int originalIndex  = source.CurrentIndex; TIn resultIn; if (!rule.TryParse(source,  out  resultIn))  { source.Move(originalIndex); return false; } result  = Convert(resultIn); return true; } }
  • 34. Map Result public class JoinText :  MapTo<char,  char[],  string>  { public JoinText(IRule<char,  char[]> rule)  :  base(rule)  {  } protected override  string  Convert(char[]  value)  =>  new  string(value); } public class MapToInteger :  MapTo<char,  string,  int>  { public MapToInteger(IRule<char,  string> rule)  :  base(rule)  {  } protected override  int Convert(string value)  =>  int.Parse(value); }
  • 35. Putting the blocks together var  quote  = new CharIs('"'); var  slash  = new CharIs(''); var  escapedQuote  = new MatchThenKeep<char,  char,  char>(slash,  quote); var  escapedSlash  = new MatchThenKeep<char,  char,  char>(slash,  slash); var  notQuote  = new Not<char,  char>(quote); var  insideQuoteChar  = new FirstMatch<char,  char>(new[]  { (IRule<char,  char>)escapedQuote, escapedSlash, notQuote }); var  insideQuote  = new Many<char,  char>(insideQuoteChar,  false); var  insideQuoteAsString  = new JoinText(insideQuote); var  openQuote  = new MatchThenKeep<char,  char,  string>(quote,   insideQuoteAsString); var  fullQuote  = new MatchThenIgnore<char,  string,  char>(openQuote,  quote); var  source  = new StringSource(raw); string  asQuote; if (fullQuote.TryParse(source,  out  asQuote)) return asQuote; source.Move(0); int asInteger; if (digitsAsInt.TryParse(source,  out  asInteger)) return asInteger; return null; var  digit  = new CharIsDigit(); var  digits  = new Many<char,  char>(digit,  true); var  digitsString  = new JoinText(digits); var  digitsAsInt  = new MapToInteger(digitsString);
  • 40. A Comparison (just the definition)
  • 41. Room for Improvement public abstract class MatchThen<Token,  TLeft,  TRight,  TOut>  :  IRule<Token,  TOut>  { readonly  IRule<Token,  TLeft> leftRule; readonly  IRule<Token,  TRight> rightRule; protected abstract TOut Combine(TLeft leftResult,  TRight rightResult); public MatchThen(IRule<Token,  TLeft> leftRule,  IRule<Token,  TRight> rightRule)  { this.leftRule  = leftRule; this.rightRule  = rightRule; } public bool  TryParse(ISource<Token> source,  out TOut result)  { int originalIndex  = source.CurrentIndex; result  = default(TOut); TLeft leftResult; if (!leftRule.TryParse(source,  out  leftResult))  { source.Move(originalIndex); return false; } TRight rightResult; if (!rightRule.TryParse(source,  out  rightResult))  { source.Move(originalIndex); return false; } result  = Combine(leftResult,  rightResult); return true; } } Out parameter :( Managing the source’s index
  • 43. An Immutable Source public interface ISource<Token>  { Token Current {  get;  } bool  HasMore {  get;  } int CurrentIndex {  get;  } void Move(int index); } public interface ISource<Token>  { Token Current {  get;  } bool  HasMore {  get;  } ISource<Token> Next(); }
  • 44. An Immutable Source public class StringSource :  ISource<char>  { readonly  string  value; int index; public StringSource(string value)  {   this.value  = value;  } public char Current  => value[index]; public int CurrentIndex  => index; public bool  HasMore  => index  < value.Length; public void Move(int index)  =>  this.index  =  index; } public class StringSource :  ISource<char>  { readonly  string  value; readonly  int index; public StringSource(string value,  int index =  0)  {   this.value  = value;  this.index  = index;  } public char Current  => value[index]; public bool  HasMore  => index  < value.Length; public ISource<char> Next()  =>   new  StringSource(value,  index +  1); }
  • 45. Ditch the Out public class Result<Token,  TValue>  { public bool  Success {  get;  } public TValue Value {  get;  } public string  Message {  get;  } public ISource<Token> Next {  get;  } public Result(bool success,  TValue value,  string message,  ISource<Token> next)  { Success = success; Value = value; Message = message; Next = next; } } public interface IRule<Token,  TValue>  { Result<Token,  TValue> TryParse(ISource<Token> source); }
  • 46. Char Matches... public abstract class CharMatches :  IRule<char,  char>  { protected abstract bool  IsCharMatch(char c); public bool  TryParse(ISource<char> source,  out char result)  { result  = default(char); if (!source.HasMore) return false; if (!IsCharMatch(source.Current)) return false; result  = source.Current; source.Move(source.CurrentIndex + 1); return true; } } public abstract class CharMatches :  IRule<char,  char>  { protected abstract bool  IsCharMatch(char c); public Result<char,  char> TryParse(ISource<char> source)  { if (!source.HasMore) return new Result<char,  char>(false,  '0',  "Unexpected  EOF",  null); if (!IsCharMatch(source.Current)) return new Result<char,  char>(false,  '0',  $"Unexpected  char:  {source.Current}",  null); return new Result<char,  char>(true,  source.Current,  null,  source.Next()); } }
  • 47. These Don’t Change public class CharIsDigit :  CharMatches  { protected override  bool  IsCharMatch(char c)  =>  char.IsDigit(c); } public class CharIs :  CharMatches  { readonly  char toMatch; public CharIs(char toMatch)  {  this.toMatch  = toMatch;  } protected override  bool  IsCharMatch(char c)  =>  c  ==  toMatch; }
  • 48. First Match public class FirstMatch<Token,  TResult>  :  IRule<Token,  TResult>  { readonly  IRule<Token,  TResult>[]  rules; public FirstMatch(IRule<Token,  TResult>[]  rules)  {  this.rules  = rules;  } public bool  TryParse(ISource<Token> source,  out TResult result)  { foreach(var  rule  in  rules)  { int originalIndex  = source.CurrentIndex; if (rule.TryParse(source,  out  result)) return true; source.Move(originalIndex); } result  = default(TResult); return false; } } public class FirstMatch<Token,  TResult>  :  IRule<Token,  TResult>  { readonly  IRule<Token,  TResult>[]  rules; public FirstMatch(IRule<Token,  TResult>[]  rules)  {  this.rules  = rules;  } public Result<Token,  TResult> TryParse(ISource<Token> source)  { foreach  (var  rule  in  rules)  { var  result  = rule.TryParse(source); if (result.Success) return result; } return new Result<Token,  TResult>(false,  default(TResult),  "No  rule  matched",  null); } }
  • 49. Match Then... public bool  TryParse(ISource<Token> source,  out TOut result)  { int originalIndex  = source.CurrentIndex; result  = default(TOut); TLeft leftResult; if (!leftRule.TryParse(source,  out  leftResult))  { source.Move(originalIndex); return false; } TRight rightResult; if (!rightRule.TryParse(source,  out  rightResult))  { source.Move(originalIndex); return false; } result  = Combine(leftResult,  rightResult); return true; } public Result<Token,  TOut> TryParse(ISource<Token> source)  { var  leftResult  = leftRule.TryParse(source); if (!leftResult.Success) return new Result<Token,  TOut>(false,  default(TOut),  leftResult.Message,  null); var  rightResult  = rightRule.TryParse(leftResult.Next); if (!rightResult.Success) return new Result<Token,  TOut>(false,  default(TOut),  rightResult.Message,  null); var  result  = Combine(leftResult.Value,  rightResult.Value); return new Result<Token,  TOut>(true,  result,  null,  rightResult.Next); }
  • 50. Invert Rule (Not) public class Not<Token,  TResult>  :  IRule<Token,  Token>  { readonly  IRule<Token,  TResult> rule; public Not(IRule<Token,  TResult> rule)  {  this.rule  = rule;  } public bool  TryParse(ISource<Token> source,  out Token result)  { result  = default(Token); if (!source.HasMore) return false; int originalIndex  = source.CurrentIndex; TResult throwAwayResult; bool  matches  = rule.TryParse(source,  out  throwAwayResult); if (matches) { source.Move(originalIndex); return false; } source.Move(originalIndex); result  = source.Current; source.Move(originalIndex  + 1); return true; } } public class Not<Token,  TResult>  :  IRule<Token,  Token>  { readonly  IRule<Token,  TResult> rule; public Not(IRule<Token,  TResult> rule)  {  this.rule  = rule;  } public Result<Token,  Token> TryParse(ISource<Token> source)  { if (!source.HasMore) return new Result<Token,  Token>(false,  default(Token),  "Unexpected   EOF",  null); var  result  = rule.TryParse(source); if (result.Success) return new Result<Token,  Token>(false,  default(Token),  "Unexpected   match",  null); return new Result<Token,  Token>(true,  source.Current,  null,   source.Next()); } }
  • 52. Still Room for Improvement public class Result<Token,  TValue>  { public bool  Success {  get;  } public TValue Value {  get;  } public string  Message {  get;  } public ISource<Token> Next {  get;  } public Result(bool success,  TValue value,  string message,  ISource<Token> next)  { Success = success; Value = value; Message = message; Next = next; } } Only valid when Success = true Only valid when Success = false
  • 53. Iteration 2.2 Discriminated Unions and Pattern Matching (sorta)
  • 54. Two States (Simple “Result” Example) public interface IResult {  } public class SuccessResult<TValue>  :  IResult  { public TValue Value {  get;  } public SuccessResult(TValue value)  {  Value = value;  } } public class ErrorResult :  IResult  { public string  Message {  get;  } public ErrorResult(string message)  {  Message = message;  } }
  • 55. Two States (The Matching) IResult result  = ParseIt(); if (result  is  SuccessResult<string>)  { var  success  = (SuccessResult<string>)result; Console.WriteLine($"SUCCESS:  {success.Value}"); }  else if (result  is  ErrorResult)  { var  error  = (ErrorResult)result; Console.WriteLine($"ERR:  {error.Message}"); }
  • 56. Pattern Matching(ish) public interface IResult<TValue>  { T  Match<T>(Func<SuccessResult<TValue>,  T> success, Func<ErrorResult<TValue>,  T> error); } public class SuccessResult<TValue>  :  IResult<TValue>  { public TValue Value {  get;  } public SuccessResult(TValue value)  {  Value = value;  } public T  Match<T>(Func<SuccessResult<TValue>,  T> success, Func<ErrorResult<TValue>,  T> error)  =>  success(this); } public class ErrorResult<TValue>  :  IResult<TValue> { public string  Message {  get;  } public ErrorResult(string message)  {  Message = message;  } public T  Match<T>(Func<SuccessResult<TValue>,  T> success, Func<ErrorResult<TValue>,  T> error)  =>  error(this); }
  • 57. Pattern Matching(ish) IResult<string> result  = ParseIt(); string  message  = result.Match( success  => $"SUCCESS:  ${success.Value}", error  => $"ERR:  {error.Message}"); Console.WriteLine(message); IResult result  = ParseIt(); if (result  is  SuccessResult<string>)  { var  success  = (SuccessResult<string>)result; Console.WriteLine($"SUCCESS:  {success.Value}"); }  else if (result  is  ErrorResult)  { var  error  = (ErrorResult)result; Console.WriteLine($"ERR:  {error.Message}"); }
  • 58. The Match Method Forces us to handle all cases Gives us an object with only valid properties for that state
  • 59. The New IResult public interface IResult<Token,  TValue>  { T  Match<T>(Func<FailResult<Token,  TValue>,  T> fail, Func<SuccessResult<Token,  TValue>,  T> success); } public class FailResult<Token,  TValue>  :  IResult<Token,  TValue>  { public string  Message {  get;  } public FailResult(string message)  {  Message = message;  } public T  Match<T>(Func<FailResult<Token,  TValue>,  T> fail, Func<SuccessResult<Token,  TValue>,  T> success)  =>  fail(this); } public class SuccessResult<Token,  TValue>  :  IResult<Token,  TValue>  { public TValue Value {  get;  } public ISource<Token> Next {  get;  } public SuccessResult(TValue value,  ISource<Token> next)  {  Value = value;  Next = next;  } public T  Match<T>(Func<FailResult<Token,  TValue>,  T> fail, Func<SuccessResult<Token,  TValue>,  T> success)  =>  success(this); }
  • 60. ISource also Represents Two States public interface ISource<Token>  { Token Current {  get;  } bool  HasMore {  get;  } ISource<Token> Next(); } Only valid when HasMore = true
  • 61. The New ISource public interface ISource<Token>  { T  Match<T>(Func<EmtySource<Token>,  T> empty, Func<SourceWithMoreContent<Token>,  T> hasMore); } public class EmtySource<Token>  :  ISource<Token>  { //  No  properties!    No  state!    Let's  just  make  it  singleton. EmtySource()  {  } public static readonly  EmtySource<Token> Instance  = new EmtySource<Token>(); public T  Match<T>(Func<EmtySource<Token>,  T> empty, Func<SourceWithMoreContent<Token>,  T> hasMore)  =>  empty(this); } public class SourceWithMoreContent<Token>  :  ISource<Token>  { readonly  Func<ISource<Token>> getNext; public SourceWithMoreContent(Token current,  Func<ISource<Token>> getNext)  {  Current = current;  this.getNext  = getNext;  } public Token Current {  get;  set;  } public ISource<Token> Next()  =>  getNext(); public T  Match<T>(Func<EmtySource<Token>,  T> empty, Func<SourceWithMoreContent<Token>,  T> hasMore)  =>  hasMore(this); }
  • 62. Make a String Source public static class StringSource { public static ISource<char> Create(string value,  int index =  0)  { if (index  >= value.Length) return EmtySource<char>.Instance; return new SourceWithMoreContent<char>(value[index],  ()  => Create(value,  index  + 1)); } } public static ISource<char> Create(string  value,  int index  = 0) => index  >= value.Length ? (ISource<char>)EmtySource<char>.Instance : new SourceWithMoreContent<char>(value[index],  ()  => Create(value,  index  + 1));
  • 63. Char Matches... public abstract class CharMatches :  IRule<char,  char>  { protected abstract bool  IsCharMatch(char c); public Result<char,  char> TryParse(ISource<char> source)  { if (!source.HasMore) return new Result<char,  char>(false,  '0',  "Unexpected  EOF",  null); if (!IsCharMatch(source.Current)) return new Result<char,  char>(false,  '0',  $"Unexpected  char:  {source.Current}",  null); return new Result<char,  char>(true,  source.Current,  null,  source.Next()); } } public abstract class CharMatches :  IRule<char,  char>  { protected abstract bool  IsCharMatch(char c); public IResult<char,  char> TryParse(ISource<char> source)  { var  result  = source.Match( empty  => (IResult<char,  char>)new FailResult<char,  char>("Unexpected  EOF"), hasMore  => { if (!IsCharMatch(hasMore.Current)) return new FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}"); return new SuccessResult<char,  char>(hasMore.Current,  hasMore.Next()); }); return result; } } public IResult<char,  char> TryParse(ISource<char> source) => source.Match( empty  => new FailResult<char,  char>("Unexpected  EOF"), hasMore  => IsCharMatch(hasMore.Current) ? new SuccessResult<char,  char>(hasMore.Current,  hasMore.Next()) : (IResult<char,  char>)new FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}") );
  • 64. Match Then... public IResult<Token,  TOut> TryParse(ISource<Token> source)  { var  leftResult  = leftRule.TryParse(source); var  finalResult  = leftResult.Match( leftFail  => new FailResult<Token,  TOut>(leftFail.Message), leftSuccess  => { var  rightResult  = rightRule.TryParse(leftSuccess.Next); var  rightFinalResult  = rightResult.Match( rightFail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(rightFail.Message), rightSuccess  => { var  finalValue  = Combine(leftSuccess.Value,  rightSuccess.Value); return new SuccessResult<Token,  TOut>(finalValue,  rightSuccess.Next); }); return rightFinalResult; }); return finalResult; } public Result<Token,  TOut> TryParse(ISource<Token> source)  { var  leftResult  = leftRule.TryParse(source); if (!leftResult.Success) return new Result<Token,  TOut>(false,  default(TOut),  leftResult.Message,  null); var  rightResult  = rightRule.TryParse(leftResult.Next); if (!rightResult.Success) return new Result<Token,  TOut>(false,  default(TOut),  rightResult.Message,  null); var  result  = Combine(leftResult.Value,  rightResult.Value); return new Result<Token,  TOut>(true,  result,  null,  rightResult.Next); } public IResult<Token,  TOut> TryParse(ISource<Token> source) => leftRule.TryParse(source).Match( leftFail  => new FailResult<Token,  TOut>(leftFail.Message), leftSuccess  => rightRule.TryParse(leftSuccess.Next).Match( rightFail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(rightFail.Message), rightSuccess  => new SuccessResult<Token,  TOut>(Combine(leftSuccess.Value,  rightSuccess.Value),   rightSuccess.Next) ) );
  • 65. Invert Rule (Not) public Result<Token,  Token> TryParse(ISource<Token> source)  { if (!source.HasMore) return new Result<Token,  Token>(false,  default(Token),  "Unexpected  EOF",  null); var  result  = rule.TryParse(source); if (result.Success) return new Result<Token,  Token>(false,  default(Token),  "Unexpected  match",  null); return new Result<Token,  Token>(true,  source.Current,  null,  source.Next()); } public IResult<Token,  Token> TryParse(ISource<Token> source) => source.Match( empty  => new FailResult<Token,  Token>("Unexpected  EOF"), current  => rule.TryParse(current).Match( fail  => new SuccessResult<Token,  Token>(current.Current,  current.Next()), success  => (IResult<Token,  Token>)new FailResult<Token,  Token>("Unexpected  match") ) );
  • 67. Let’s Be Honest All these `new` objects are ugly. var  quote  = new CharIs('"'); var  slash  = new CharIs(''); var  escapedQuote  = new MatchThenKeep<char,  char,   char>(slash,  quote); var  escapedSlash  = new MatchThenKeep<char,  char,   char>(slash,  slash); var  notQuote  = new Not<char,  char>(quote); var  insideQuoteChar  = new FirstMatch<char,  char>(new[]  { (IRule<char,  char>)escapedQuote, escapedSlash, notQuote }); var  insideQuote  = new Many<char,  char>(insideQuoteChar,   false); var  insideQuoteAsString  = new JoinText(insideQuote); var  openQuote  = new MatchThenKeep<char,  char,   string>(quote,  insideQuoteAsString); var  fullQuote  = new MatchThenIgnore<char,  string,   char>(openQuote,  quote);
  • 68. Also Single method interfaces are lame*. It’s effectively a delegate. public interface IRule<Token,  TValue>  { IResult<Token,  TValue> TryParse(ISource<Token> source); } *In  a  non-­scientific  poll  of  people  who  agree  with  me,  100%  of   respondents  confirmed  this  statement.    Do  not  question  its  validity.
  • 69. Iteration 3.0 Functions as First Class Citizens
  • 70. A Rule is a Delegate is a Function public interface IRule<Token,  TValue>  { IResult<Token,  TValue> TryParse(ISource<Token> source); } public delegate  IResult<Token,  TValue> Rule<Token,  TValue>(ISource<Token> source);
  • 71. Char Matches... public abstract class CharMatches :  IRule<char,  char>  { protected abstract bool  IsCharMatch(char c); public IResult<char,  char> TryParse(ISource<char> source) =>  source.Match( empty =>  new FailResult<char,  char>("Unexpected EOF"), hasMore  =>  IsCharMatch(hasMore.Current) ?  new  SuccessResult<char,  char>(hasMore.Current,  hasMore.Next()) :  (IResult<char,  char>)new  FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}") ); } public static class Rules { public static Rule<char,  char> CharMatches(Func<char,  bool> isMatch) =>  (source)  =>  source.Match( empty =>  new FailResult<char,  char>("Unexpected EOF"), hasMore  =>  isMatch(hasMore.Current) ?  new  SuccessResult<char,  char>(hasMore.Current,  hasMore.Next()) :  (IResult<char,  char>)new  FailResult<char,  char>($"Unexpected  char:  {hasMore.Current}") ); } public static Rule<char,  char> CharIsDigit()  => CharMatches(char.IsDigit); public static Rule<char,  char> CharIs(char c)  => CharMatches(x  => x  == c);
  • 72. Then (Keep|Ignore) public static Rule<Token,  TOut> MatchThen<Token,  TLeft,  TRight,  TOut>(this Rule<Token,  TLeft> leftRule,  Rule<Token,   TRight> rightRule,  Func<TLeft,  TRight,  TOut> convert) => (source)  => leftRule(source).Match( leftFail  => new FailResult<Token,  TOut>(leftFail.Message), leftSuccess  => rightRule(leftSuccess.Next).Match( rightFail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(rightFail.Message), rightSuccess  => new SuccessResult<Token,  TOut>(convert(leftSuccess.Value,  rightSuccess.Value),   rightSuccess.Next) ) ); public static Rule<Token,  TRight> MatchThenKeep<Token,  TLeft,  TRight>(this Rule<Token,  TLeft> leftRule,  Rule<Token,   TRight> rightRule) => MatchThen(leftRule,  rightRule,  (left,  right)  => right); public static Rule<Token,  TLeft> MatchThenIgnore<Token,  TLeft,  TRight>(this Rule<Token,  TLeft> leftRule,  Rule<Token,   TRight> rightRule) => MatchThen(leftRule,  rightRule,  (left,  right)  => left);
  • 73. Not, MapTo, JoinText, MapToInteger public static Rule<Token,  Token> Not<Token,  TResult>(this Rule<Token,  TResult> rule) => (source)  => source.Match( empty  => new FailResult<Token,  Token>("Unexpected  EOF"), current  => rule(current).Match( fail  => new SuccessResult<Token,  Token>(current.Current,  current.Next()), success  => (IResult<Token,  Token>)new FailResult<Token,  Token>("Unexpected  match") ) ); public static Rule<Token,  TOut> MapTo<Token,  TIn,  TOut>(this Rule<Token,  TIn> rule,  Func<TIn,  TOut> convert) => (source)  => rule(source).Match( fail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(fail.Message), success  => new SuccessResult<Token,  TOut>(convert(success.Value),  success.Next) ); public static Rule<char,  string> JoinText(this Rule<char,  char[]> rule) => MapTo(rule,  (x)  => new string(x)); public static Rule<char,  int> MapToInteger(this Rule<char,  string> rule) => MapTo(rule,  (x)  => int.Parse(x));
  • 74. Example Usage var  quote  = Rules.CharIs('"'); var  slash  = Rules.CharIs(''); var  escapedQuote  =  Rules.MatchThenKeep(slash,  quote); var  escapedSlash  = slash.MatchThenKeep(slash);
  • 75. The Original 2.0 Definition var  quote  = new CharIs('"'); var  slash  = new CharIs(''); var  escapedQuote  = new MatchThenKeep<char,  char,  char>(slash,  quote); var  escapedSlash  = new MatchThenKeep<char,  char,  char>(slash,  slash); var  notQuote  = new Not<char,  char>(quote); var  insideQuoteChar  = new FirstMatch<char,  char>(new[]  { (IRule<char,  char>)escapedQuote, escapedSlash, notQuote }); var  insideQuote  = new Many<char,  char>(insideQuoteChar,  false); var  insideQuoteAsString  = new JoinText(insideQuote); var  openQuote  = new MatchThenKeep<char,  char,  string>(quote,   insideQuoteAsString); var  fullQuote  = new MatchThenIgnore<char,  string,  char>(openQuote,  quote); var  source  = new StringSource(raw); string  asQuote; if (fullQuote.TryParse(source,  out  asQuote)) return asQuote; source.Move(0); int asInteger; if (digitsAsInt.TryParse(source,  out  asInteger)) return asInteger; return null; var  digit  = new CharIsDigit(); var  digits  = new Many<char,  char>(digit,  true); var  digitsString  = new JoinText(digits); var  digitsAsInt  = new MapToInteger(digitsString);
  • 76. The Updated 3.0 Definition var  quote  = Rules.CharIs('"'); var  slash  = Rules.CharIs(''); var  escapedQuote  = slash.MatchThenKeep(quote); var  escapedSlash  = slash.MatchThenKeep(slash); var  notQuote  = quote.Not(); var  fullQuote  = quote .MatchThenKeep( Rules.FirstMatch( escapedQuote, escapedSlash, notQuote ).Many().JoinText() ) .MatchThenIgnore(quote); var  finalResult  = Rules.FirstMatch( fullQuote.MapTo(x  => (object)x), digit.MapTo(x  => (object)x) ); var  source  = StringSource.Create(raw); return finalResult(source).Match( fail  => null, success  => success.Value ); var  integer  = Rules.CharIsDigit() .Many(true) .JoinText() .MapToInteger();
  • 79. A Comparison V1 -> V3 (Just Definition)
  • 80. Looks Great! My co-workers are going to kill me
  • 81. Is it a good idea? public static Rule<Token,  Token> Not<Token,  TResult>(this Rule<Token,  TResult> rule) => (source)  => source.Match( empty  => new FailResult<Token,  Token>("Unexpected  EOF"), current  => rule(current).Match( fail  => new SuccessResult<Token,  Token>(current.Current,  current.Next()), success  => (IResult<Token,  Token>)new FailResult<Token,  Token>("Unexpected  match") ) ); public static Rule<Token,  TOut> MapTo<Token,  TIn,  TOut>(this Rule<Token,  TIn> rule,  Func<TIn,  TOut> convert) => (source)  => rule(source).Match( fail  => (IResult<Token,  TOut>)new FailResult<Token,  TOut>(fail.Message), success  => new SuccessResult<Token,  TOut>(convert(success.Value),  success.Next) ); public static Rule<char,  string> JoinText(this Rule<char,  char[]> rule) => MapTo(rule,  (x)  => new string(x)); public static Rule<char,  int> MapToInteger(this Rule<char,  string> rule) => MapTo(rule,  (x)  => int.Parse(x));
  • 82. Limitations “At Zombocom, the only limit… is yourself.” 1. Makes a LOT of short-lived objects (ISources, IResults). 2. As written currently, you will end up with the entire thing in memory. 3. Visual Studio’s Intellisense struggles with nested lambdas. 4. Frequently requires casts to solve type inference problems. 5. It’s not very C#.
  • 84. Iterations Iteration 1.0: Procedural Iteration 2.0: Making Compositional with OOP Iteration 2.1: Immutability Iteration 2.2: Discriminated Unions and Pattern Matching Iteration 3.0: Functions as First Class Citizens
  • 85. That’s All Thanks for coming and staying awake!