diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index d9d36fab2..2d7309738 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -86,7 +86,7 @@ RootValue allocRootValue(Value * v)
 }
 
 
-void printValue(std::ostream & str, std::set<const Value *> & seen, const Value & v)
+void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v)
 {
     checkInterrupt();
 
@@ -115,32 +115,32 @@ void printValue(std::ostream & str, std::set<const Value *> & seen, const Value
         str << "null";
         break;
     case tAttrs: {
-        seen.insert(&v);
-        str << "{ ";
-        for (auto & i : v.attrs->lexicographicOrder()) {
-            str << i->name << " = ";
-            if (seen.count(i->value))
-                str << "<REPEAT>";
-            else
+        if (!v.attrs->empty() && !seen.insert(v.attrs).second)
+            str << "<REPEAT>";
+        else {
+            str << "{ ";
+            for (auto & i : v.attrs->lexicographicOrder()) {
+                str << i->name << " = ";
                 printValue(str, seen, *i->value);
-            str << "; ";
+                str << "; ";
+            }
+            str << "}";
         }
-        str << "}";
         break;
     }
     case tList1:
     case tList2:
     case tListN:
-        seen.insert(&v);
-        str << "[ ";
-        for (auto v2 : v.listItems()) {
-            if (seen.count(v2))
-                str << "<REPEAT>";
-            else
+        if (v.listSize() && !seen.insert(v.listElems()).second)
+            str << "<REPEAT>";
+        else {
+            str << "[ ";
+            for (auto v2 : v.listItems()) {
                 printValue(str, seen, *v2);
-            str << " ";
+                str << " ";
+            }
+            str << "]";
         }
-        str << "]";
         break;
     case tThunk:
     case tApp:
@@ -169,7 +169,7 @@ void printValue(std::ostream & str, std::set<const Value *> & seen, const Value
 
 std::ostream & operator << (std::ostream & str, const Value & v)
 {
-    std::set<const Value *> seen;
+    std::set<const void *> seen;
     printValue(str, seen, v);
     return str;
 }
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index 84c4d09f8..d0fa93e92 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -115,7 +115,7 @@ private:
     InternalType internalType;
 
     friend std::string showType(const Value & v);
-    friend void printValue(std::ostream & str, std::set<const Value *> & seen, const Value & v);
+    friend void printValue(std::ostream & str, std::set<const void *> & seen, const Value & v);
 
 public: