defineVar :: Env -> String -> LispVal -> IOThrowsError LispVal
defineVar envRef var value = do 
  alreadyDefined <- liftIO $ isBound envRef var 
  if alreadyDefined 
  then setVar envRef var value >> return value
  else liftIO $ do 
    valueRef <- newIORef value
    env <- readIORef envRef
    writeIORef envRef ((var, valueRef) : env)
    return value
defineVar :: Env -> String -> LispVal -> IOThrowsError LispVal
defineVar envRef var value = do 
  alreadyDefined <- liftIO $ isBound envRef var 
  if alreadyDefined 
  then setVar envRef var value >> return value
  else liftIO $ do 
    valueRef <- newIORef value
    env <- readIORef envRef
    writeIORef envRef ((var, valueRef) : env)
    return value
defineVar envRef var value = do 
  alreadyDefined <- liftIO $ isBound envRef var 
  if alreadyDefined 
  then setVar envRef var value >> return value
  else liftIO $ do 
    valueRef <- newIORef value
    env <- readIORef envRef
    writeIORef envRef ((var, valueRef) : env)
    return value