diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,17 @@
 
 `hslua-list` uses [PVP Versioning](https://pvp.haskell.org).
 
+## hslua-list-1.1.2
+
+Released 2024-09-20.
+
+-   Lists can now be constructed from iterators.
+
+-   Added method `:at` to access list elements by index; negative
+    indices are counted from the end. A second value can be
+    passed, which will be returned if there is no item at the
+    given index.
+
 ## hslua-list-1.1.1
 
 Released 2023-03-17.
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright © 2021-2023 Albert Krewinkel
+Copyright © 2021-2024 Albert Krewinkel
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the
diff --git a/cbits/listmod.c b/cbits/listmod.c
--- a/cbits/listmod.c
+++ b/cbits/listmod.c
@@ -45,12 +45,31 @@
 ** given.
 */
 static int list_new (lua_State *L) {
-  lua_settop(L, 2);
   if (lua_isnoneornil(L, 2)) {
+    lua_settop(L, 1);
     lua_newtable(L);
-    lua_remove(L, 2);
+  } else if (lua_type(L, 2) == LUA_TFUNCTION) {
+    /* try to use the function as an iterator */
+    lua_settop(L, 5);
+    lua_newtable(L);     /* create new table */
+    /* move the table and toclose variable out of the way */
+    lua_insert(L, 2);
+    lua_insert(L, 3);
+    lua_toclose(L, 3);
+    lua_Integer i = 0;   /* list index */
+    do {
+      lua_pushvalue(L, 4);  /* iterator function */
+      lua_pushvalue(L, 5);  /* state */
+      lua_rotate(L, 6, -1); /* move control variable to the top */
+      lua_call(L, 2, 1);    /* get next list element */
+      /* add return value to table */
+      lua_pushvalue(L, -1);
+      lua_rawseti(L, 2, ++i);
+    } while (lua_type(L, -1) != LUA_TNIL);
+    lua_settop(L, 2);      /* keep only the new table */
   } else {
     luaL_checktype(L, 2, LUA_TTABLE);
+    lua_settop(L, 2);
   }
   lua_pushvalue(L, 1);
   lua_setmetatable(L, 2);
@@ -58,6 +77,27 @@
 }
 
 /*
+** Returns the item at that index, or the default value if no item was
+** found.
+*/
+static int list_at (lua_State *L) {
+  lua_settop(L, 3); /* table; index; default value */
+  lua_Integer i = luaL_checkinteger(L, 2);
+  lua_Integer len = luaL_len(L, 1);
+
+  if (i < -len || i > len) {
+    /* out of bounds, do not try to get a value */
+    return 1;        /* return the default value */
+  }
+
+  i = i >= 0 ? i : len + i + 1;
+  if (lua_rawgeti(L, 1, i) == LUA_TNIL) {
+    lua_pop(L, 1);  /* pop result; default value is now at the top */
+  };
+  return 1;
+}
+
+/*
 ** Creates a shallow clone of the given list; the clone will contain
 ** only the list elements, not any other elements that might have been
 ** present.
@@ -343,6 +383,7 @@
   {"__concat", list_concat},
   {"__eq", list_eq},
   {"__tostring", list_tostring},
+  {"at", list_at},
   {"clone", list_clone},
   {"extend", list_extend},
   {"filter", list_filter},
diff --git a/hslua-list.cabal b/hslua-list.cabal
--- a/hslua-list.cabal
+++ b/hslua-list.cabal
@@ -1,6 +1,6 @@
 cabal-version:       2.2
 name:                hslua-list
-version:             1.1.1
+version:             1.1.2
 synopsis:            Opinionated, but extensible Lua list type.
 description:         List type for Lua, with a Haskell interface.
 homepage:            https://hslua.org/
@@ -9,7 +9,7 @@
 license-file:        LICENSE
 author:              Albert Krewinkel
 maintainer:          Albert Krewinkel <tarleb@hslua.org>
-copyright:           © 2022-2023 Albert Krewinkel
+copyright:           © 2022-2024 Albert Krewinkel
 category:            Foreign
 build-type:          Simple
 extra-doc-files:     README.md
@@ -20,8 +20,11 @@
                    , GHC == 8.8.4
                    , GHC == 8.10.7
                    , GHC == 9.0.2
-                   , GHC == 9.2.5
-                   , GHC == 9.4.4
+                   , GHC == 9.2.8
+                   , GHC == 9.4.8
+                   , GHC == 9.6.5
+                   , GHC == 9.8.2
+                   , GHC == 9.10.1
 
 source-repository head
   type:                git
diff --git a/src/HsLua/List.hs b/src/HsLua/List.hs
--- a/src/HsLua/List.hs
+++ b/src/HsLua/List.hs
@@ -1,6 +1,6 @@
 {-# LANGUAGE LambdaCase           #-}
 {- |
-Copyright  : © 2021-2023 Albert Krewinkel
+Copyright  : © 2021-2024 Albert Krewinkel
 License    : MIT
 Maintainer : Albert Krewinkel <tarleb@hslua.org>
 
diff --git a/test/test-hslua-list.hs b/test/test-hslua-list.hs
--- a/test/test-hslua-list.hs
+++ b/test/test-hslua-list.hs
@@ -3,7 +3,7 @@
 {-# LANGUAGE TypeApplications    #-}
 {-|
 Module      : Main
-Copyright   : © 2021-2023 Albert Krewinkel
+Copyright   : © 2021-2024 Albert Krewinkel
 License     : MIT
 Maintainer  : Albert Krewinkel <tarleb@hslua.org>
 
diff --git a/test/test-list.lua b/test/test-list.lua
--- a/test/test-list.lua
+++ b/test/test-list.lua
@@ -16,6 +16,33 @@
       test('returns a new list if called without args', function ()
         assert.are_same(List(), {})
       end),
+
+      test('works with a simple iterator function', function ()
+        local text = "two words"
+        local result = List(string.gmatch(text, '[^%s]+'))
+        assert.are_same({'two', 'words'}, result)
+      end),
+
+      test('can convert an interator into a list', function ()
+        local tbl = {one = 1, two = 2}
+        local result = List(next, tbl, nil)
+        result:sort()
+        assert.are_same(List{'one', 'two'}, result)
+      end),
+    },
+
+    group 'at' {
+      test('gets the item at the given index', function ()
+        assert.are_equal(2, List{1, 1, 2, 3, 5}:at(3))
+      end),
+
+      test('negative indices are counted from the end', function ()
+        assert.are_equal(5, List{1, 1, 2, 3, 5}:at(-1))
+      end),
+
+      test('the default value is returned if no item is found', function ()
+        assert.are_equal(0, List{1, 1, 2, 3, 5}:at(9, 0))
+      end)
     },
 
     group 'clone' {
