1 /** This module implements a variety of classes derived from Function. */ 2 module generald.functions; 3 4 import std.typecons, std.traits; 5 6 alias Maybe = Nullable; 7 8 /// A class representing a function. 9 abstract class Function(A, B) 10 { 11 abstract B opCall(A); 12 alias InputType = A; 13 alias OutputType = B; 14 } 15 16 /// Template for converting a function to Function instance. 17 class RealFunction(alias f, A=ParameterTypeTuple!f[0], B=ReturnType!f) : Function!(A, B) 18 { 19 pragma(msg, "RealFunction(", A.stringof, " -> ", ParameterTypeTuple!f[0].stringof, " -> ", ReturnType!f.stringof, " -> ", B.stringof, ")"); 20 override B opCall(A x) 21 { 22 return f(x); 23 } 24 mixin Singleton; 25 } 26 27 /// 28 unittest 29 { 30 static int f(long x) 31 { 32 return cast(int)((x >> 32) ^ (x & ((1UL << 32) - 1))); 33 } 34 static assert (is (RealFunction!f : Function!(long, int))); 35 static assert (is (RealFunction!(f, int, int) : Function!(int, int))); 36 static assert (is (RealFunction!(f, int, long) : Function!(int, long))); 37 static assert (is (RealFunction!(f, long, long) : Function!(long, long))); 38 } 39 40 /// Identity function. 41 T id(T)(T x) 42 { 43 return x; 44 } 45 46 /// ditto 47 alias IdentityFunction(T) = RealFunction!(id!T); 48 49 /// 50 unittest 51 { 52 auto f = IdentityFunction!int.get; 53 assert (f(0) == 0); 54 } 55 56 /// Compose two Functions. 57 class ComposedFunction(A, B, C, D) : Function!(A, D) 58 if (is (B : C)) 59 { 60 Function!(A, B) f; 61 Function!(C, D) g; 62 this (Function!(A, B) f, Function!(C, D) g) 63 { 64 this.f = f; 65 this.g = g; 66 } 67 override D opCall(A x) 68 { 69 return g(f(x)); 70 } 71 } 72 73 /// ditto 74 auto compose(F, G)(F f, G g) 75 if (is (F : Function!(F.InputType, F.OutputType)) && 76 is (G : Function!(G.InputType, G.OutputType)) && 77 is (F.OutputType : G.InputType)) 78 { 79 return new ComposedFunction!(F.InputType, F.OutputType, G.InputType, G.OutputType)(f, g); 80 } 81 82 /// 83 unittest 84 { 85 auto f = RealFunction!(triple!int).get.compose(RealFunction!(increment!int).get); 86 auto g = RealFunction!(increment!int).get.compose(RealFunction!(triple!int).get); 87 assert (f(0) == 1); 88 assert (f(1) == 4); 89 assert (g(0) == 3); 90 assert (g(1) == 6); 91 } 92 93 /// Curry a function. 94 class CurriedFunction(A, B, C) : Function!(A, Function!(B, C)) 95 { 96 Function!(Tuple!(A, B), C) uncurried; 97 this (Function!(Tuple!(A, B), C) uncurried) 98 { 99 this.uncurried = uncurried; 100 } 101 class Partial : Function!(B, C) 102 { 103 A x; 104 this (A x) 105 { 106 this.x = x; 107 } 108 override C opCall(B x) 109 { 110 return uncurried(this.x.tuple(x)); 111 } 112 } 113 override Function!(B, C) opCall(A x) 114 { 115 return new Partial(x); 116 } 117 } 118 119 /// ditto 120 auto curry(F)(F f) 121 { 122 static if (is (F.InputType : Tuple!(A, B), A, B)) 123 return new CurriedFunction!(A, B, F.OutputType)(f); 124 else static assert (false); 125 } 126 127 /// 128 unittest 129 { 130 static class F : Function!(Tuple!(int, int), int) 131 { 132 override int opCall(Tuple!(int, int) x) 133 { 134 return x[0] + x[1]; 135 } 136 mixin Singleton; 137 } 138 auto cf = F.get.curry; 139 static assert (is (typeof (cf) : Function!(int, Function!(int, int)))); 140 } 141 142 /// Uncurry a function. 143 class UncurriedFunction(A, B, C) : Function!(Tuple!(A, B), C) 144 { 145 Function!(A, Function!(B, C)) curried; 146 this (Function!(A, Function!(B, C)) curried) 147 { 148 this.curried = curried; 149 } 150 override C opCall(Tuple!(A, B) x) 151 { 152 return curried(x[0])(x[1]); 153 } 154 } 155 156 /// ditto 157 auto uncurry(F)(F f) 158 { 159 static if (is (F.OutputType == Function!(B, C), B, C)) 160 return new UncurriedFunction!(F.InputType, B, C)(f); 161 else static assert (false); 162 } 163 164 /// 165 unittest 166 { 167 static class G : Function!(int, Function!(int, int)) 168 { 169 170 class g : Function!(int, int) 171 { 172 int x; 173 this (int x) 174 { 175 this.x = x; 176 } 177 override int opCall(int x) 178 { 179 return this.x + x; 180 } 181 } 182 override Function!(int, int) opCall(int x) 183 { 184 return new g(x); 185 } 186 mixin Singleton; 187 } 188 auto ug = G.get.uncurry; 189 static assert (is (typeof (ug) : Function!(Tuple!(int, int), int))); 190 } 191 192 /// Function which always return Null. 193 Maybe!A nothing(A)() 194 { 195 return Maybe!A(); 196 } 197 198 /// Return function for Maybe. 199 Maybe!A just(A)(A x) 200 { 201 return Maybe!A(x); 202 } 203 /// ditto 204 alias maybeReturn(A) = just!A; 205 /// ditto 206 alias MaybeReturn(A) = RealFunction!(maybeReturn!A); 207 208 /// Bind function for Maybe: (a -> Maybe b) -> (Maybe a -> Maybe b). 209 class MaybeBind(A, B) : Function!(Maybe!A, Maybe!B) 210 { 211 Function!(A, Maybe!B) f; 212 this (Function!(A, Maybe!B) f) 213 { 214 this.f = f; 215 } 216 override Maybe!B opCall(Maybe!A x) 217 { 218 if (x.isNull) 219 return nothing!B; 220 return f(x.get); 221 } 222 } 223 224 /// ditto 225 auto maybeBind(F)(F f) 226 { 227 static if (is (F.OutputType : Maybe!B, B)) 228 return new MaybeBind!(F.InputType, B)(f); 229 else static assert (false); 230 } 231 232 /// Map function for Maybe. 233 auto maybeMap(F)(F f) 234 if (is (F : Function!(A, B), A, B)) 235 { 236 return f.compose(MaybeReturn!(F.OutputType).get).maybeBind; 237 } 238 239 /// 240 unittest 241 { 242 auto maybeId = maybeMap(RealFunction!(id!int).get); 243 assert (maybeId(just(0)) == just(0)); 244 } 245 246 /// Compose two Functions f and g where f emits a Maybe!B and g takes a B. 247 auto maybeCompose(F, G)(F f, G g) 248 { 249 return f.compose(g.maybeBind); 250 } 251 252 /// 253 unittest 254 { 255 auto c = RealFunction!(collatz!int).get; 256 auto lc = c.maybeCompose(c).maybeCompose(c); 257 auto rc = c.maybeCompose(c.maybeCompose(c)); 258 foreach (i; 0..10) 259 assert (lc(i).maybeEqual(rc(i))); 260 } 261 262 /// Function from Maybe to void can be constructed from a Function to void. 263 class MaybeSink(A) : Function!(Maybe!A, void) 264 { 265 Function!(A, void) sink; 266 this (Function!(A, void) sink) 267 { 268 this.sink = sink; 269 } 270 override void opCall(Maybe!A x) 271 { 272 if (x.isNull) 273 return; 274 sink(x); 275 } 276 } 277 278 /// ditto 279 auto maybeSink(S)(S sink) 280 if (is (S : Function!(A, void), A)) 281 { 282 return new MaybeSink!(S.InputType)(sink); 283 } 284 285 /// Maybe do something, and return null. 286 class MaybeNothing(A, B, C=void) : Function!(A, Maybe!B) 287 { 288 Function!(A, C) sink; 289 this (Function!(A, C) sink) 290 { 291 this.sink = sink; 292 } 293 override Maybe!B opCall(A x) 294 { 295 sink(x); 296 return nothing!B; 297 } 298 } 299 300 /// ditto 301 auto maybeNothing(B, F)(F f) 302 { 303 return new MaybeNothing!(F.InputType, B, F.OutputType)(f); 304 } 305 306 307 /// Either type. 308 struct Either(A, B) 309 if (!is (A : B) && !is (B : A)) 310 { 311 this (A a) 312 { 313 this.nonNull = true; 314 this.which = false; 315 this._a = a; 316 } 317 this (B b) 318 { 319 this.nonNull = true; 320 this.which = true; 321 this._b = b; 322 } 323 typeof (this) opAssign(A a) 324 { 325 this.nonNull = true; 326 this.which = false; 327 this._a = a; 328 return this; 329 } 330 typeof (this) opAssign(B b) 331 { 332 this.nonNull = true; 333 this.which = true; 334 this._b = b; 335 return this; 336 } 337 string toString() 338 { 339 import std.conv; 340 if (!which) 341 return _a.to!string; 342 else 343 return _b.to!string; 344 } 345 private: 346 bool nonNull, which; 347 A _a; 348 B _b; 349 @property A a() 350 in 351 { 352 assert (this.nonNull); 353 assert (!this.which); 354 } 355 body 356 { 357 return _a; 358 } 359 @property B b() 360 in 361 { 362 assert (this.nonNull); 363 assert ( this.which); 364 } 365 body 366 { 367 return _b; 368 } 369 } 370 371 /// Tuple of functions, which takes an Either. 372 class EitherFunction(A, B, C) : Function!(Either!(A, B), C) 373 { 374 Function!(A, C) f; 375 Function!(B, C) g; 376 this (Function!(A, C) f, Function!(B, C) g) 377 { 378 this.f = f; 379 this.g = g; 380 } 381 override C opCall(Either!(A, B) x) 382 { 383 if (!x.which) 384 return f(x.a); 385 else 386 return g(x.b); 387 } 388 } 389 390 /// ditto 391 auto eitherFunction(F, G)(F f, G g) 392 if (is (F.OutputType == G.OutputType)) 393 { 394 return new EitherFunction!(F.InputType, G.InputType, F.OutputType)(f, g); 395 } 396 397 /// Function to Either. 398 alias LeftEither(A, B) = RealFunction!(left!(B, A)); 399 400 /// ditto 401 alias RightEither(A, B) = RealFunction!(right!(A, B)); 402 403 /// Either!(, B) functor at A. 404 Either!(A, B) left(B, A)(A a) 405 { 406 Either!(A, B) x; 407 x = a; 408 return x; 409 } 410 411 /// Either!(A, ) functor at B. 412 Either!(A, B) right(A, B)(B b) 413 { 414 Either!(A, B) x; 415 x = b; 416 return x; 417 } 418 419 /// Function from and to Either. 420 auto eitherEither(F, G)(F f, G g) 421 { 422 return eitherFunction( 423 f.compose(LeftEither!(F.OutputType, G.OutputType).get), 424 g.compose(RightEither!(F.OutputType, G.OutputType).get)); 425 } 426 427 /// Tuple of functions, which returns a Tuple. 428 class FunctionTuple(A, B, C) : Function!(A, Tuple!(B, C)) 429 { 430 Function!(A, B) f; 431 Function!(A, C) g; 432 this (Function!(A, B) f, Function!(A, C) g) 433 { 434 this.f = f; 435 this.g = g; 436 } 437 override Tuple!(B, C) opCall(A x) 438 { 439 return tuple(f(x), g(x)); 440 } 441 } 442 443 /// ditto 444 auto functionTuple(F, G)(F f, G g) 445 if (is (F.InputType == G.InputType)) 446 { 447 return new FunctionTuple!(F.InputType, F.OutputType, G.OutputType)(f, g); 448 } 449 450 /// Function from Tuple. 451 auto tupleLeft(T)(T x) 452 { 453 return x[0]; 454 } 455 456 /// ditto 457 auto tupleRight(T)(T x) 458 { 459 return x[1]; 460 } 461 462 /// ditto 463 alias TupleLeft(A, B) = RealFunction!(tupleLeft!(Tuple!(A, B))); 464 465 /// ditto 466 alias TupleRight(A, B) = RealFunction!(tupleRight!(Tuple!(A, B))); 467 468 /// Function from and to Tuple. 469 auto tupleTuple(F, G)(F f, G g) 470 { 471 return functionTuple( 472 TupleLeft!(F.InputType, G.InputType).get.compose(f), 473 TupleRight!(F.InputType, G.InputType).get.compose(g)); 474 } 475 476 /// Function from Tuple of Maybe to Maybe of Tuple. 477 auto maybeTuple(TM)(TM x) 478 { 479 if (x[0].isNull || x[1].isNull) 480 return nothing!(Tuple!(typeof (x[0].get), typeof (x[1].get))); 481 return just(x[0].get.tuple(x[1].get)); 482 } 483 484 /// ditto 485 alias MaybeTuple(A, B) = RealFunction!(maybeTuple!(Tuple!(Maybe!A, Maybe!B))); 486 487 /// Returns the function which swaps the components of the given tuple. 488 auto swapper(A, B)() 489 { 490 return TupleRight!(A, B).get.functionTuple(TupleLeft!(A, B).get); 491 } 492 493 /// Compose with swapper. 494 auto swapResult(F)(F f) 495 { 496 return f.compose(swapper!(F.OutputType.Types[0], F.OutputType.Types[1])()); 497 } 498 499 /// 500 unittest 501 { 502 auto x = new Maybe!int[4]; 503 auto y = new Maybe!int[4]; 504 auto z = new Maybe!(Tuple!(int, int))[4]; 505 x[0] = 2; x[1] = 3; 506 y[0] = 5, y[2] = 7; 507 z[0] = 5.tuple(2); 508 auto p = IdentityFunction!(Tuple!(Maybe!int, Maybe!int)).get 509 .swapResult.compose(MaybeTuple!(int, int).get); 510 foreach (i; 0..4) 511 assert (p(x[i].tuple(y[i])).maybeEqual(z[i])); 512 } 513 514 /// (a -> b) -> (a -> (b, a)) 515 auto functionTupleIdentity(F)(F f) 516 { 517 return f.functionTuple(IdentityFunction!(F.InputType).get); 518 } 519 520 /// (a -> b) -> ((a, c) -> (b, c)) 521 auto tupleTupleIdentity(B, F)(F f) 522 { 523 return f.tupleTuple(IdentityFunction!B.get); 524 } 525 526 /// (a -> b) -> (a|b -> b) 527 auto eitherFunctionIdentity(F)(F f) 528 { 529 return f.eitherFunction(IdentityFunction!(F.OutputType).get); 530 } 531 532 /// (a -> b) -> (a|c -> b|c) 533 auto eitherEitherIdentity(B, F)(F f) 534 { 535 return f.eitherEither(IdentityFunction!B.get); 536 } 537 538 /// 539 unittest 540 { 541 static class TestedFunction : Function!(int, string) 542 { 543 override string opCall(int x) 544 { 545 import std.math, std.conv; 546 return sqrt(real(1) + x * x).to!string; 547 } 548 mixin Singleton; 549 } 550 auto t = TestedFunction.get; 551 auto 552 t0 = t.functionTupleIdentity, 553 t1 = t.tupleTupleIdentity!(int[]), 554 t2 = t.eitherFunctionIdentity, 555 t3 = t.eitherEitherIdentity!(int[]); 556 static assert (is (typeof (t0) : Function!(int, Tuple!(string, int)))); 557 static assert (is (typeof (t1) : Function!(Tuple!(int, int[]), Tuple!(string, int[])))); 558 static assert (is (typeof (t2) : Function!(Either!(int, string), string))); 559 static assert (is (typeof (t3) : Function!(Either!(int, int[]), Either!(string, int[])))); 560 } 561 562 /// Either of functions, which returns an Either. 563 class FunctionEither(A, B, C) : Function!(A, Either!(B, C)) 564 { 565 Either!(Function!(A, B), Function!(A, C)) f; 566 this (Either!(Function!(A, B), Function!(A, C)) f) 567 { 568 this.f = f; 569 } 570 this (Function!(A, B) f) 571 { 572 this.f = f; 573 } 574 this (Function!(A, C) f) 575 { 576 this.f = f; 577 } 578 override Either!(B, C) opCall(A x) 579 { 580 if (!f.which) 581 return f.a()(x).left!C; 582 else 583 return f.b()(x).right!B; 584 } 585 } 586 587 /// ditto 588 auto functionEitherLeft(C, F)(F f) 589 { 590 static if (is (F : Function!(A, B), A, B)) 591 return new FunctionEither!(A, B, C)(f); 592 else static assert (false); 593 } 594 595 /// ditto 596 auto functionEitherRight(B, F)(F f) 597 { 598 static if (is (F : Function!(A, C), A, C)) 599 return new FunctionEither!(A, B, C)(f); 600 else static assert (false); 601 } 602 603 /// 604 unittest 605 { 606 static real lreal(int x) 607 { 608 import std.math; 609 return PI * x; 610 } 611 static string rstring(int x) 612 { 613 import std.conv; 614 return x.to!string; 615 } 616 auto fl = RealFunction!lreal.get.functionEitherLeft!string; 617 auto fr = RealFunction!rstring.get.functionEitherRight!real; 618 static assert (is (typeof (fl) == typeof (fr))); 619 } 620 621 /// Either of functions, which takes a Tuple. 622 class TupleFunction(A, B, C) : Function!(Tuple!(A, B), C) 623 { 624 Either!(Function!(A, C), Function!(B, C)) f; 625 this (Either!(Function!(A, C), Function!(B, C)) f) 626 { 627 this.f = f; 628 } 629 this (Function!(A, C) f) 630 { 631 this.f = f; 632 } 633 this (Function!(B, C) f) 634 { 635 this.f = f; 636 } 637 override C opCall(Tuple!(A, B) x) 638 { 639 if (!f.which) 640 return f.a()(x[0]); 641 else 642 return f.b()(x[1]); 643 } 644 } 645 646 /// ditto 647 auto leftTupleFunction(B, F)(F f) 648 { 649 return new TupleFunction!(F.InputType, B, F.OutputType)(f); 650 } 651 652 /// ditto 653 auto rightTupleFunction(A, F)(F f) 654 { 655 return new TupleFunction!(A, F.InputType, F.OutputType)(f); 656 } 657 658 /// 659 unittest 660 { 661 static string cts(char x) 662 { 663 import std.conv : to; 664 return x.to!string; 665 } 666 static string rts(real x) 667 { 668 import std.conv : to; 669 return x.to!string; 670 } 671 auto l = RealFunction!cts.get.leftTupleFunction!real; 672 auto r = RealFunction!rts.get.rightTupleFunction!char; 673 static assert (is (typeof (l) == typeof (r))); 674 } 675 676 /// Takues an array of functions and return a function to array. 677 class FunctionArray(A, B) : Function!(A, B[]) 678 { 679 Function!(A, B)[] fs; 680 this (Function!(A, B)[] fs) 681 { 682 this.fs = fs; 683 } 684 override B[] opCall(A x) 685 { 686 B[] ret; 687 foreach (f; fs) 688 ret ~= f(x); 689 return ret; 690 } 691 } 692 693 /// ditto 694 auto functionArray(F)(F[] fs) 695 { 696 return new FunctionArray!(F.InputType, F.OutputType)(fs); 697 } 698 699 /// Map function for Array. 700 class ArrayMap(A, B) : Function!(A[], B[]) 701 { 702 Function!(A, B) f; 703 this (Function!(A, B) f) 704 { 705 this.f = f; 706 } 707 override B[] opCall(A[] xs) 708 { 709 B[] ret; 710 foreach (x; xs) 711 ret ~= f(x); 712 return ret; 713 } 714 } 715 716 /// ditto 717 auto arrayMap(F)(F f) 718 { 719 return new ArrayMap!(F.InputType, F.OutputType)(f); 720 } 721 722 /// Bind function for Array. 723 class ArrayBind(A, B) : Function!(A[], B[]) 724 { 725 Function!(A, B[]) f; 726 this (Function!(A, B[]) f) 727 { 728 this.f = f; 729 } 730 override B[] opCall(A[] xs) 731 { 732 B[] ret; 733 foreach (x; xs) 734 ret ~= f(x); 735 return ret; 736 } 737 } 738 739 /// ditto 740 auto arrayBind(F)(F f) 741 { 742 return new ArrayBind!(F.InputType, ElementType!(F.OutputType)); 743 } 744 745 /// Return function for Array. 746 auto arrayOnly(A)(A x) 747 { 748 return [x]; 749 } 750 /// ditto 751 alias arrayReturn(A) = arrayOnly!A; 752 /// ditto 753 alias ArrayReturn(A) = RealFunction!(arrayReturn!A); 754 755 /// Function from Array to void can be constructed from a Function to void. 756 class ArraySink(A) : Function!(A[], void) 757 { 758 Function!(A, void) sink; 759 this (Function!(A, void) sink) 760 { 761 this.sink = sink; 762 } 763 override void opCall(A[] xs) 764 { 765 foreach (x; xs) 766 sink(x); 767 } 768 } 769 770 /// ditto 771 auto arraySink(S)(S sink) 772 if (is (S : Function!(A, void), A)) 773 { 774 return new ArraySink!(S.InputType)(sink); 775 } 776 777 /// 778 unittest 779 { 780 import std.stdio, std.range, std.array; 781 RealFunction!(writeln!int).get.arraySink()(10.iota.array); 782 } 783 784 /// Take an array of functions and return a function from and to array. 785 class ArrayArray(A, B) : Function!(A[], B[]) 786 { 787 Function!(A, B)[] fs; 788 this (Function!(A, B)[] fs) 789 { 790 this.fs = fs; 791 } 792 @property size_t length() 793 { 794 return fs.length; 795 } 796 override B[] opCall(A[] xs) 797 in 798 { 799 assert (length == xs.length); 800 } 801 body 802 { 803 import std.range : zip; 804 B[] ret; 805 foreach (fx; fs.zip(xs)) 806 ret ~= fx[0](fx[1]); 807 return ret; 808 } 809 } 810 811 /// ditto 812 auto arrayArray(FS)(FS fs) 813 { 814 import std.range : ElementType; 815 return new ArrayArray!(ElementType!FS.InputType, ElementType!FS.OutputType)(fs); 816 } 817 818 /// 819 unittest 820 { 821 static class Adder : Function!(int, int) 822 { 823 int added; 824 this (int added) 825 { 826 this.added = added; 827 } 828 override int opCall(int x) 829 { 830 return x + added; 831 } 832 } 833 import std.range : iota; 834 import std.array : array; 835 Function!(int, int)[] adders; 836 foreach_reverse (i; 0..5) 837 adders ~= new Adder(i + 1); 838 assert (adders.arrayArray()(5.iota.array) == [5, 5, 5, 5, 5]); 839 } 840 841 /// Singleton pattern. 842 mixin template Singleton(Flag!"hideConstructor" hideConstructor = Yes.hideConstructor) 843 { 844 static typeof (this) get() 845 { 846 static typeof (this) instance; 847 if (instance is null) 848 return instance = new typeof (this)(); 849 return instance; 850 } 851 static if (hideConstructor) 852 private this () 853 { 854 } 855 } 856 857 debug 858 { 859 class Printer(T) : Function!(T, void) 860 { 861 override void opCall(T x) 862 { 863 import std.stdio; 864 writeln(x); 865 } 866 mixin Singleton; 867 } 868 auto autoPrint(F)(F f) 869 { 870 return f.compose(Printer!(F.OutputType).get); 871 } 872 auto autoPrintJustOnly(F)(F f) 873 { 874 static if (is (F.OutputType : Maybe!B, B)) 875 return f.compose(Printer!B.get.maybeSink); 876 else static assert (false); 877 } 878 } 879 880 version (unittest) 881 { 882 T triple(T)(T x) 883 { 884 return x * 3; 885 } 886 T increment(T)(T x) 887 { 888 return x + 1; 889 } 890 Maybe!T collatz(T)(T x) 891 { 892 if (x <= 1) 893 return nothing!T; 894 if (x & 1) 895 return just(x.triple.increment); 896 return just(x / 2); 897 } 898 bool maybeEqual(T)(Maybe!T x, Maybe!T y) 899 { 900 if (x.isNull || y.isNull) 901 return x.isNull && y.isNull; 902 return x.get == y.get; 903 } 904 } 905 906 unittest 907 { 908 import std.stdio; 909 stderr.writeln("unittest passed!"); 910 }