Skip to content

Instantly share code, notes, and snippets.

@pwm
Last active March 15, 2018 09:43
Show Gist options
  • Save pwm/d7d8c2548c7b271c417ac7ee62eb9e88 to your computer and use it in GitHub Desktop.
Save pwm/d7d8c2548c7b271c417ac7ee62eb9e88 to your computer and use it in GitHub Desktop.
Sum type musings
<?php
declare(strict_types=1);
class UnitOfTemp {
public const C = 'C';
public const F = 'F';
public const K = 'K';
public const UNITS = [
self::C,
self::F,
self::K,
];
/** @var string */
private $value;
public function __construct(string $value) {
if (! \in_array($value, self::UNITS, true)) {
throw new \InvalidArgumentException(sprintf('Unit %s is unknown', $value));
}
$this->value = $value;
}
public function toValue(): string {
return $this->value;
}
}
class TempSum1 {
/** @var float */
private $value;
/** @var UnitOfTemp */
private $unit;
public function __construct(float $value, UnitOfTemp $unit) {
$this->value = $value;
$this->unit = $unit;
}
public function match(callable $c, callable $f, callable $k) {
switch ($this->unit->toValue()) {
case UnitOfTemp::C: return $c($this->value);
case UnitOfTemp::F: return $f($this->value);
case UnitOfTemp::K: return $k($this->value);
}
}
}
class TempSum2 {
/** @var float */
private $value;
/** @var string */
private $unit;
private const C = 'C';
private const F = 'F';
private const K = 'K';
public static function celsius(float $value): self {
return new self($value, self::C);
}
public static function fahrenheit(float $value): self {
return new self($value, self::F);
}
public static function kelvin(float $value): self {
return new self($value, self::K);
}
public function match(callable $c, callable $f, callable $k) {
switch ($this->unit) {
case self::C: return $c($this->value);
case self::F: return $f($this->value);
case self::K: return $k($this->value);
}
}
private function __construct(float $value, string $unit) {
$this->value = $value;
$this->unit = $unit;
}
}
// ====
function isFever1(TempSum1 $t): bool {
return $t->match(
function ($c) { return $c >= 37; },
function ($f) { return $f >= 99; },
function ($k) { return $k >= 310; }
);
}
function isFever2(TempSum2 $t): bool {
return $t->match(
function ($c) { return $c >= 37; },
function ($f) { return $f >= 99; },
function ($k) { return $k >= 310; }
);
}
assert(false === isFever1(new TempSum1(35, new UnitOfTemp(UnitOfTemp::C))));
assert(true === isFever1(new TempSum1(39, new UnitOfTemp(UnitOfTemp::C))));
assert(false === isFever1(new TempSum1(39, new UnitOfTemp(UnitOfTemp::F))));
assert(true === isFever1(new TempSum1(99, new UnitOfTemp(UnitOfTemp::F))));
assert(false === isFever1(new TempSum1(99, new UnitOfTemp(UnitOfTemp::K))));
assert(true === isFever1(new TempSum1(350, new UnitOfTemp(UnitOfTemp::K))));
assert(false === isFever2(TempSum2::celsius(35)));
assert(true === isFever2(TempSum2::celsius(39)));
assert(false === isFever2(TempSum2::fahrenheit(39)));
assert(true === isFever2(TempSum2::fahrenheit(99)));
assert(false === isFever2(TempSum2::kelvin(99)));
assert(true === isFever2(TempSum2::kelvin(350)));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment