The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!perl
use warnings FATAL => 'all';
use strict;

use Test::More tests => 4;
use Test::Fatal;

{
    package MyTC;

    use Function::Parameters qw(:strict);

    method new(
        $class:
        $name,
        $check,
        $get_message = fun ($value) {
            "Validation failed for constraint '$name' with value '$value'"
        },
    ) {
        bless {
            name => $name,
            check => $check,
            get_message => $get_message,
        }, $class
    }

    method check($value) {
        $self->{check}($value)
    }

    method get_message($value) {
        $self->{get_message}($value)
    }
}

use Function::Parameters do {
    use Function::Parameters qw(:strict);

    my %Types = (
        TEvenNum  => MyTC->new('even number'  => fun ($n) { $n =~ /^[0-9]+\z/ && $n % 2 == 0 }),
        TShortStr => MyTC->new('short string' => fun ($s) { length($s) < 10 }),
        Any       => MyTC->new('any value'    => fun ($a) { 1 }),
    );
    +{
        fun => {
            strict => 1,
            reify_type => sub { $Types{ $_[0] } || $Types{Any} },
        },
    }
};

fun foo(TEvenNum $x, TShortStr $y) {
    "$x/$y"
}

is foo(42, "hello"), "42/hello";
like exception { foo 41, "hello" },       qr{\bValidation failed for constraint 'even number' with value '41'};
like exception { foo 42, "1234567890~" }, qr{\bValidation failed for constraint 'short string' with value '1234567890~'};
like exception { foo 41, "1234567890~" }, qr{\bValidation failed for constraint 'even number' with value '41'};