Task
Solve Dinesman's multiple dwelling problem but in a way that most naturally follows the problem statement given below.

Solutions are allowed (but not required) to parse and interpret the problem text, but should remain flexible and should state what changes to the problem text are allowed. Flexibility and ease of expression are valued.

Examples may be be split into "setup", "problem statement", and "output" sections where the ease and naturalness of stating the problem and getting an answer, as well as the ease and flexibility of modifying the problem are the primary concerns.

Example output should be shown here, as well as any comments on the examples flexibility.



The problem
Baker, Cooper, Fletcher, Miller, and Smith live on different floors of an apartment house that contains only five floors.


   Baker does not live on the top floor.
   Cooper does not live on the bottom floor. 
   Fletcher does not live on either the top or the bottom floor.
   Miller lives on a higher floor than does Cooper.
   Smith does not live on a floor adjacent to Fletcher's. 
   Fletcher does not live on a floor adjacent to Cooper's.

Where does everyone live?

local wrap, yield = coroutine.wrap, coroutine.yield
local function perm(n)
    local r = {}
    for i=1,n do r[i]=i end    
  return wrap(function()
    local function swap(m)      
      if m==0 then  
        yield(r)
      else
        for i=m,1,-1 do
          r[i],r[m]=r[m],r[i]
          swap(m-1)
          r[i],r[m]=r[m],r[i]
        end    
      end
    end
    swap(n)
  end)
end
 
local function iden(...)return ... end
local function imap(t,f)
  local r,fn = {m=imap, c=table.concat, u=table.unpack}, f or iden
  for i=1,#t do r[i]=fn(t[i])end
  return r
end
 
local tenants = {'Baker', 'Cooper', 'Fletcher', 'Miller', 'Smith'}
 
local conds = {
  'Baker  ~= TOP',
  'Cooper ~= BOTTOM',
  'Fletcher ~= TOP and Fletcher~= BOTTOM',
  'Miller > Cooper',
  'Smith + 1 ~= Fletcher and Smith - 1 ~= Fletcher',
  'Cooper + 1 ~= Fletcher and Cooper - 1 ~= Fletcher',
}
 
local function makePredicate(conds, tenants)
  return load('return function('..imap(tenants):c','..
    ') return ' ..
    imap(conds,function(c)
      return string.format("(%s)",c) 
    end):c"and "..
    " end ",'-',nil,{TOP=5, BOTTOM=1})()
end
 
local function solve (conds, tenants)
  local try, pred, upk = perm(#tenants), makePredicate(conds, tenants), table.unpack
  local answer = try()
  while answer and not pred(upk(answer)) do answer = try()end
  if answer then
    local floor = 0
    return imap(answer, function(person) 
        floor=floor+1; 
        return string.format(" %s lives on floor %d",tenants[floor],person) 
    end):c"\n"
  else
    return nil, 'no solution'
  end  
end
 
print(solve (conds, tenants))