Zebra puzzle

You are encouraged to solve this task according to the task description, using any language you may know.
The Zebra puzzle, a.k.a. Einstein's Riddle,
is a logic puzzle which is to be solved programmatically.



It has several variants, one of them this:

   There are five houses.
   The English man lives in the red house.
   The Swede has a dog.
   The Dane drinks tea.
   The green house is immediately to the left of the white house.
   They drink coffee in the green house.
   The man who smokes Pall Mall has birds.
   In the yellow house they smoke Dunhill.
   In the middle house they drink milk.
   The Norwegian lives in the first house.
   The man who smokes Blend lives in the house next to the house with cats.
   In a house next to the house where they have a horse, they smoke Dunhill.
   The man who smokes Blue Master drinks beer.
   The German smokes Prince.
   The Norwegian lives next to the blue house.
   They drink water in a house next to the house where they smoke Blend. 

The question is, who owns the zebra?

Additionally, list the solution for all the houses.

Optionally, show the solution is unique.



Related tasks

   Dinesman's multiple-dwelling problem
   Twelve statements


 
processor EinsteinSolver
  @: [{|{}|}]; // A list of possible relations, start with one relation with an empty tuple
  $ -> \(
    when <[](1..)> do
      def variableRange: $(1);
      @EinsteinSolver: [($@EinsteinSolver(1) join {|{by $variableRange...}|})];
      $(2..last) -> #
  \) -> !VOID
 
  sink isFact
    def fact: $;
    def parts: [$... -> {$}];
    @EinsteinSolver: [$@EinsteinSolver... -> \(
      def new: ($ matching {|$fact|});
      @: $;
      $parts... -> @: ($@ notMatching {| $ |});
      ($new union $@) !
    \)];
  end isFact
 
  operator (a nextTo&{byField:, bMinusA:} b)
    data ES_temp__ <"1"> local
    @EinsteinSolver: [$@EinsteinSolver... -> \(
      def in: $;
      def temp: {| $... -> {$, ES_temp__: $(byField)::raw} |};
      def numbers: [$temp({ES_temp__:})... -> $.ES_temp__];
      $numbers... -> \(
        def aNumber: $;
        def bNumbers: [$bMinusA... -> $ + $aNumber];
        def new: ($temp matching {| {$a, ES_temp__: $aNumber} |});
        @: ($new union (($temp notMatching {| $a |}) notMatching {| {ES_temp__: $aNumber} |}));
        $numbers... -> \(<~ ?($bNumbers <[<=$>]>)> $! \) -> @: ($@ notMatching {| {$b, ES_temp__: $} |});
        ($in matching $@) !
      \) !
    \)];
  end nextTo
 
  source solutions&{required:}
    templates resolve&{rows:}
      when <?($rows <=1>)?($::count <=1>)> do $ !
      when <?($::count <$rows..>)> do
        def in: $;
        def selected: [$...] -> $(1);
        ($in minus {|$selected|}) -> resolve&{rows: $rows} ! // Alternative solutions
        @: $;
        $selected... -> {$} -> @: ($@ notMatching {| $ |});
        [$@ -> resolve&{rows: $rows-1}] -> \(
            when <~=[]> do
              $... -> {| $..., $selected |} !
        \) !
    end resolve
    [$@EinsteinSolver... -> resolve&{rows: $required}] !
  end solutions
end EinsteinSolver
 
def numbers: [1..5 -> (no: $)];
def nationalities: [['Englishman', 'Swede', 'Dane', 'Norwegian', 'German']... -> (nationality:$)];
def colours: [['red', 'green', 'white', 'yellow', 'blue']... -> (colour:$)];
def pets: [['dog', 'birds', 'cats', 'horse', 'zebra']... -> (pet:$)];
def drinks: [['tea', 'coffee', 'milk', 'beer', 'water']... -> (drink:$)];
def smokes: [['Pall Mall', 'Dunhill', 'Blend', 'Blue Master', 'Prince']... -> (smoke: $)];
 
 
def solutions: [$numbers, $nationalities, $colours, $pets, $drinks, $smokes] -> \(
  def solver: $ -> EinsteinSolver;
 
  {nationality: 'Englishman', colour: 'red'} -> !solver::isFact
  {nationality: 'Swede', pet: 'dog'} -> !solver::isFact
  {nationality: 'Dane', drink: 'tea'} -> !solver::isFact
  ({colour: 'green'} solver::nextTo&{byField: :(no:), bMinusA: [1]} {colour: 'white'}) -> !VOID
  {drink: 'coffee', colour: 'green'} -> !solver::isFact
  {smoke: 'Pall Mall', pet: 'birds'} -> !solver::isFact
  {colour: 'yellow', smoke: 'Dunhill'} -> !solver::isFact
  {no: 3, drink: 'milk'} -> !solver::isFact
  {nationality: 'Norwegian', no: 1} -> !solver::isFact
  ({smoke: 'Blend'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {pet: 'cats'}) -> !VOID
  ({smoke: 'Dunhill'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {pet: 'horse'}) -> !VOID
  {smoke: 'Blue Master', drink: 'beer'} -> !solver::isFact
  {nationality: 'German', smoke: 'Prince'} -> !solver::isFact
  ({nationality: 'Norwegian'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {colour: 'blue'}) -> !VOID
  ({drink: 'water'} solver::nextTo&{byField: :(no:), bMinusA: [-1, 1]} {smoke: 'Blend'}) -> !VOID
 
  $solver::solutions&{required: 5}!
\);
 
$solutions... -> ($ matching {| {pet: 'zebra'} |}) ... -> 'The $.nationality; owns the zebra.
 
' -> !OUT::write
 
$solutions -> \[i]('Solution $i;:
$... -> '$;
';
'! \)... -> !OUT::write
'No more solutions
' -> !OUT::write
 