Skip to content

Instantly share code, notes, and snippets.

@isaacabraham
Last active June 10, 2024 10:48
Show Gist options
  • Save isaacabraham/55b7ce49abad892e4930b138aca556c0 to your computer and use it in GitHub Desktop.
Save isaacabraham/55b7ce49abad892e4930b138aca556c0 to your computer and use it in GitHub Desktop.
An implementation of LINQ using OO composition features.
module LinqOo =
/// Selects a value into another shape.
type ISelectable<'a, 'b> =
abstract Select: 'a -> 'b
/// Filters a value.
type IFilterable<'a> =
abstract Filter: 'a -> bool
type ICollectable<'a, 'b> =
abstract Collect: 'a -> 'b list
/// A class that can perform operations on collections of items.
type LinqOO<'a>(data: 'a list) =
/// Selects all values in a list into another shape.
member _.Select(selector: ISelectable<_, _>) =
let data: 'b list = [
for item in data do
yield selector.Select item
]
LinqOO data
/// Filters a list of values.
member _.Filter(filterer: IFilterable<_>) =
let data: 'a list = [
for item in data do
if filterer.Filter item then
yield item
]
LinqOO data
member _.Collect(collector: ICollectable<_, _>) =
let data: 'b list = [
for item in data do
yield! collector.Collect item
]
LinqOO data
/// Exits the LinqOO pipeline.
member _.Exit() = data
open LinqOo
/// A class that can square numbers.
type SquareNumber() =
interface ISelectable<int, int> with
member _.Select(x: int) = x * x
type GetChars() =
interface ICollectable<string, char> with
member _.Collect(item: string) = item.ToCharArray() |> List.ofArray
/// A class that can filter even numbers.
type EvenNumbers() =
interface IFilterable<int> with
member _.Filter(x: int) = x % 2 = 0
type NotEqual(char) =
interface IFilterable<char> with
member _.Filter(x) = x <> char
/// A class that can convert a value to a string.
type ToString<'a>() =
interface ISelectable<'a, string> with
member _.Select(item: 'a) = item.ToString()
/// A class that can prefix a number string.
type Prefix() =
interface ISelectable<string, string> with
member _.Select(item: string) = $"The number is {item}"
let numbers =
LinqOO([ 1..10 ])
.Select(SquareNumber())
.Filter(EvenNumbers())
.Select(ToString<_>())
.Select(Prefix())
.Collect(GetChars())
.Filter(NotEqual ' ')
.Exit()
// VS the below...
open System.Linq
[ 1..10 ]
.Select(fun x -> x * x)
.Where(fun x -> x % 2 = 0)
.Select(fun x -> x.ToString())
.Select(fun x -> $"The number is {x}")
.SelectMany(fun x -> x.ToCharArray() |> Seq.ofArray)
.Where(fun x -> x <> ' ')
// or this...
[ 1..10 ]
|> List.map (fun x -> x * x)
|> List.filter (fun x -> x % 2 = 0)
|> List.map string
|> List.map (fun x -> $"The number is {x}")
|> List.collect (fun x -> x.ToCharArray() |> List.ofArray)
|> List.filter (fun x -> x <> ' ')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment