[NB: Un seguimiento de este repositorio usando GPT-4 se puede encontrar aquí.]
Los modelos de idiomas grandes (LLM) como ChatGPT y Claude han demostrado habilidades de programación impresionantes, y son capaces de resolver problemas en una amplia gama de idiomas y sus taxonomías. A pesar de estos éxitos, cierto escepticismo persiste en la medida en que estos modelos exhiben cualquier apreciación subyacente de las reglas sintácticas y operativas que subyacen a estos idiomas ( versus la memorización de patrones de los datos de capacitación).
En este repositorio de ingeniería rápida, las habilidades de programación de ChatGPT se exploran utilizando un lenguaje arbitrario específico de dominio (DSL). Los DSL representan un sustrato atractivo para estudiar las capacidades de inferencia de LLM porque son novedosos y menos probables que se han encontrado y memorizados ampliamente durante el entrenamiento 1 . Como tal, permiten una prueba más directa de la medida en que los LLM pueden inferir las reglas de los nuevos lenguajes de programación de una manera de disparo .
Aquí, el lenguaje específico del dominio SIL (lenguaje de integración de simetría) se seleccionó por dos razones. En primer lugar, es extremadamente improbable que ChatGPT haya estado expuesto a cualquier código de SIL durante la capacitación, ya que es un DSL interno desarrollado por un fondo de cobertura pesado tecnológico llamado Symmetry Investments. En segundo lugar, como lenguaje de programación, tiene algunas características interesantes para que el modelo se reproduzca (por ejemplo, es un lenguaje funcional que enfatiza la expresividad, pero carece de expresiones let como en Haskell o Ocaml).

Después de algunas indicaciones de código de ejemplo, ChatGPT intenta escribir código en un DSL funcional novedoso conocido como 'SIL'.
A continuación se muestra una colección de indicaciones que consisten en ejemplos cortos de código SIL que resaltan su funcionalidad. Después de solicitar ChATGPT con la tarea y proporcionar muestras de código SIL (consulte la figura a continuación; el historial de inmediato y los ejemplos de código SIL también están en este repositorio), le pedí que implementara una serie de tareas de programación convencionales en SIL.
En las secciones a continuación, muestro algunos de los scripts de código SIL de ejemplo con los que se solicitó el modelo (el conjunto completo de ejemplos se puede encontrar aquí) y sus intentos de implementar varios problemas en SIL.
El primer mensaje es un script para manejar alguna funcionalidad del servidor de correo. Como tal, difiere enormemente del tipo de problema que posteriormente pediré a ChatGPT a resolver, pero ilustra parte de la sintaxis, las estructuras de datos y los aspectos funcionales de SIL (p |> ,
// example of using IMAP IDLE to run rules on new mail
import imap
moveMessages(session,ids,target) => if (ids.length > 0 ) then imap.moveUIDs(session,ids,target) else false
login = imap.ImapLogin(environment( " IMAP_USER " ),environment( " IMAP_PASS " ))
server = imap.ImapServer( " imap.fastmail.com " , " 993 " )
session = imap.Session(server,login, true ,imap.Options(debugMode: true )) | > imap.openConnection | > imap.login
rules=[ [
[ " INBOX/0receipts " ,
[
" FROM [email protected] " ,
" FROM interactivebrokers.com " ,
]],
[ " Junk " ,
[
" FROM Tapatalk " ,
]],
[ " INBOX/newsletters " ,
[
" FROM [email protected] " , " HEADER X-mailer mailgun " , " HEADER X-mailer WPMailSMTP/Mailer/mailgun 2.4.0 " , " HEADER X-mailer nlserver " ,
" FROM hbr.org " , " FROM elliottwave.com " , " OR FROM cio.com FROM cio.co.uk " , " FROM substack.com " , " FROM eaglealpha.com " ,
" FROM haaretz.com " , " FROM gavekal.com " , " FROM go.weka.io " , " FROM marketing.weka.io " , ` HEADER list-unsubscribe "" ` ,
` HEADER list-Id "" ` , ` HEADER list-Post "" ` , ` HEADER list-owner"" ` , ` HEADER Precedence bulk ` , ` HEADER Precedence list ` ,
` HEADER list-bounces "" ` , ` HEADER list-help "" ` , ` HEADER List-Unsubscribe "" ` , " FROM no-reply " ,
]],
[ " INBOX/notifications " ,
[
` KEYWORD "$IsNotification" ` , " FROM [email protected] " , " FROM [email protected] " , " FROM skillcast.com " ,
" FROM reedmac.co.uk " , " FROM [email protected] " , " FROM [email protected] " , " FROM [email protected] " ,
]],
]
runRules(Session,Rules) => Rules
| > map(target => [target[ 0 ],(target[ 1 ] | > map(term => imap.search(Session,term).ids))])
| > mapa(set => moveMessages(Session,set[ 1 ] | > join,set[ 0 ]))
runRulesBox(Session,Rules,Mailbox) => {
imap.select(Session,Mailbox)
in runRules (Session,Rules)
}
inboxes=[ " INBOX " ]
result = inboxes | > mapa(inbox => runRulesBox(session,rules,imap.Mailbox(session,inbox)))
print(result)
import parallel;
threadFunction(x) => {
imap.idle(session)
in inboxes | > mapa(inbox => runRulesBox(session,rules,imap.Mailbox(session,inbox)))
}
parallel.runEvents((x) => false ,[threadFunction]) El segundo código de ejemplo indica de manera similar a resaltar algunas características de este DSL para el modelo, e introduce algunas nuevas funciones de biblioteca estándar, como iota y fold .
import imap
import imap_config
import string
// Get the configuration from the environment and command line.
config = imap_config.getConfig(commandLineArguments)
// -------------------------------------------------------------------------------------------------
// Some helper functions.
//
// Firstly, a function to join an array of strings.
joinFields(flds, sep) => {
len(flds) > 0 | > enforce( " Cannot join an empty array. " )
in fold (flds[ 1 :$], (str, fld) => str ~ sep ~ fld, flds[ 0 ])
}
// Secondly, a field formatter which strips the field prefix and pads to a fixed width.
// E.g., ("From: [email protected]" |> fmtField(20)) == "[email protected] "
fmtField(field, width) => {
pad(str) => iota(width - len(str)) | > fold((a, i) => a ~ " " , str)
in field
| > string .split( " : " )[ 1 :$]
| > joinFields( " : " )
| > pad
}
// And thirdly, a function which concatenates the headers into a formatted string.
fmtHeaders(outStr, headers) => {
outStr ~ " " ~ joinFields(headers, " | " ) ~ " n "
}
// -------------------------------------------------------------------------------------------------
// Connect to the inbox.
creds = imap.ImapLogin(config.user, config.pass)
server = imap.ImapServer(config.host, config.port)
session =
imap.Session(server, creds)
| > imap.openConnection()
| > imap.login()
inbox = imap.Mailbox(session, " INBOX " )
// Get the number of messages in the inbox.
msgCount = imap.status(session, inbox).messages
// Select the default inbox.
inbox | > imap.examine(session, _)
// Get the headers (date, from and subject) for each message, from oldest to newest, format and
// print them.
headers =
iota(msgCount)
| > map(id => " # " ~ toString(id + 1 ))
| > map(id =>
imap.fetchFields(session, id, " date from subject " ).lines
| > map(hdr => fmtField(hdr, 40 )))
| > fold(fmtHeaders, " INBOX: n " )
print(headers)La tercera muestra de código ilustra además algunas de las características inusuales de este DSL, con el objetivo de que ChatGPT las usará en sus propias implementaciones a continuación.
// This script will search for emails and match new issue numbers with resolutions to report the
// number of outstanding alerts.
import imap
import * from imap.query
import imap_config
import dates
import string
// Get the configuration from the environment and command line.
config = imap_config.getConfig(commandLineArguments)
// Connect to the inbox.
creds = imap.ImapLogin(config.user, config.pass)
server = imap.ImapServer(config.host, config.port)
session =
imap.Session(server, creds)
| > imap.openConnection()
| > imap.login()
inbox = imap.Mailbox(session, " support " )
// Select the default inbox.
inbox | > imap.examine(session, _)
// These criteria are common for both our searches.
commonCrit = imap.Query()
| > and(from( ` [email protected] ` ))
| > and(sentSince(dates. Date ( 2020 , 5 , 13 )))
// Get each of the alerts and resolutions from the past week (13-19 May 2020).
alertMsgIds =
imap.search(session, imap.Query(subject( " Alert: new issue " )) | > and(commonCrit)).ids
resolutionMsgIds =
imap.search(session, imap.Query(subject( " Resolution: issue " )) | > and(commonCrit)).ids
// A function to get the alert ID from a message subject.
getAlertId(msgId) => {
imap.fetchFields(session, toString (msgId), " subject " ).lines[ 0 ]
| > string .split()[$ - 1 ]
}
// A function to remove an entry from a table whether it's there or not.
removeIfExists(tbl, key) => {
if find( keys (tbl), key) == [] then
tbl
else
removeEntry(tbl, key)
}
// Now find those alerts which have no resolution. Firstly the subject for each alert, get the
// issue number end and store it in a table.
allAlertTable = alertMsgIds | > fold((tbl, msgId) => addEntry(tbl, getAlertId(msgId), msgId), {})
// Go through the resolutions and remove their corresponding alerts from the table.
unresolvedAlertTable =
resolutionMsgIds | > fold((tbl, msgId) => removeIfExists(tbl, getAlertId(msgId)), allAlertTable)
// Create a report with the date of the unresolved alerts.
report =
keys (unresolvedAlertTable)
| > map(alertId => {
msgId = unresolvedAlertTable[alertId] | > toString
in [ alertId
, imap.fetchFields(session, msgId, " date " ).lines[ 0 ]
, imap.fetchText(session, msgId).lines[ 0 ]
]
})
| > fold((outStr, tuple) => {
outStr ~ " Issue: " ~ tuple[ 0 ] ~ " n " ~ tuple[ 1 ] ~ " n Summary: " ~ tuple[ 2 ] ~ " n "
}, " n UNRESOLVED ISSUES FROM THE PAST 10 DAYS: nn " )
// Close the session.
imap.closeConnection(session)
// Print the report last.
print(report) Como primer ejercicio, le pedí al modelo que implementara una base de datos relacional muy simple en SIL, con funcionalidades básicas como comparar e imprimir la diferencia entre dos estructuras de datos (tenga en cuenta que // denota comentarios en SIL).
// Here, ChatGPT was prompted to write a a very simple, schematic relational database in SIL
// This prompt proved too general, perhaps, and after requesting further information, I prompted the model to generate a simple, schematic database with functionalities such as "compare" and "diff" for two or more tables
users = [ { " id " : 1 , " name " : " John Doe " , " email " : " [email protected] " }, { " id " : 2 , " name " : " Jane Smith " , " email " : " [email protected] " }, { " id " : 3 , " name " : " Bob Johnson " , " email " : " [email protected] " },]
orders = [ { " id " : 1 , " user_id " : 1 , " product " : " Widget " , " quantity " : 2 , " price " : 19.99 }, { " id " : 2 , " user_id " : 2 , " product " : " Gadget " , " quantity " : 1 , " price " : 29.99 }, { " id " : 3 , " user_id " : 3 , " product " : " Thingamajig " , " quantity " : 3 , " price " : 39.99 },]
// Compare two tables
compareTables(table1, table2) => {
table1 == table2
}
// Diff two tables
diffTables(table1, table2) => {
table1.filter(i => ! table2.includes(i))
}
print(compareTables(users, users)) // true
print(diffTables(users, orders)) // [{"id": 1, "name": "John Doe", "email": "[email protected]"}]La implementación de algoritmos de clasificación es una pregunta de entrevista de ingeniería de software arquetípica. Aquí, le pedí a ChatGPT que implementara Bubblesort (conceptualmente el algoritmo de clasificación más básico) en SIL. A continuación se muestra la respuesta:
bubbleSort(arr) => {
for i in 1 ... len(arr) {
for j in 1 ... len(arr) - i {
if (arr[j] > arr[j + 1 ]) {
temp = arr[j]
arr[j] = arr[j + 1 ]
arr[j + 1 ] = temp
}
}
}
arr
}
arr = [ 4 , 6 , 1 , 3 , 5 , 2 ]
print(bubbleSort(arr)) Aunque este script es, de hecho, una implementación en funcionamiento de Bubblesort, el modelo ignora ampliamente los aspectos funcionales de SIL. Por ejemplo, esta implementación de Bubblesort usando for en lugar de recursión.
A continuación, solicité al modelo a escribir un script para calcular la mediana de una lista (respuesta generada a continuación). Esta fue, quizás, una de las respuestas menos satisfactorias. En primer lugar, a pesar de las declaraciones de if/else que aparecen en el código SIL de ejemplo con el que solicité el modelo, la sintaxis en este código generado es incorrecto. En segundo lugar, el chatGPT alucina (o asume) la presencia de un módulo llamado math y un sort de función buil-in (estos son supuestos razonables, pero disminuye significativamente la complejidad del problema provocado).
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
import math
// Function to compute the median of a list of integers
median(numbers) => {
// Sort the list of numbers
sortedNumbers = sort(numbers)
// Get the middle index of the sorted list
middleIndex = math.floor(len(sortedNumbers) / 2 )
// If the list has an odd number of elements, return the middle element
if len(sortedNumbers) % 2 == 1 :
return sortedNumbers[middleIndex]
// Otherwise, return the average of the two middle elements
else :
return (sortedNumbers[middleIndex - 1 ] + sortedNumbers[middleIndex]) / 2
}
A continuación, ChatGPT se le solicitó a implementar el algoritmo de vecinos K -Nearest en SIL. Este es en realidad el resultado de dos indicaciones (como se describe en el bloque de código generado a continuación), porque el modelo alucina/asume un módulo llamado distances en el primer intento. En el segundo intento, solicité que implementara el algoritmo sin asumir la existencia de este módulo.
El rendimiento de Chatgpt aquí es mixto. En primer lugar, en algunos casos, ignora los aspectos funcionales de SIL (como la implementación de A for Loop en el primer intento. En otras partes de la implementación, sin embargo, aprecia que SIL es funcional, y emplea a los operadores de |> y map con precisión. Notablemente, el modelo parece que las vinculaciones let que no se presentan en el código de ejemplo con el que se solicitó.
// Note that this is the fusion of two separate scripts generated by ChatGPT to solve the k-nearest neighbours algorithm, as described in the comments below
// Overall, these attempts seem reasonable, but it does appear to hallucinate "let" bindings which do not feature in the example code with which it was prompted. This is likely due to conflating the functionality of SIL code with OCaml or F#
// Attempt 1:
// This is the first ChatGPT attempt when prompted to generate a script for the k-nearest neighbours algorithm
// In this case, it assumes (or hallucinates) a library called "distances"
import distances
// Define a point as a tuple of x and y coordinates
type Point = (num, num)
// Find the distance between two points
distance(p1: Point, p2: Point) => {
let xDistance = p1[ 0 ] - p2[ 0 ]
let yDistance = p1[ 1 ] - p2[ 1 ]
in sqrt (xDistance * xDistance + yDistance * yDistance)
}
// Find the k nearest points to a given point
kNearest(point: Point, points: [Point], k: num) => {
// Compute the distances between the given point and all other points
let distances = points | > map(p => (p, distance(point, p)))
// Sort the points by distance
distances = distances | > sort((d1, d2) => d1[ 1 ] < d2[ 1 ])
// Return the k closest points
in distances[:k] | > map(d => d[ 0 ])
}
// Attempt 2:
// Next, ChatGPT is prompted to generate a script without importing the questionable "distances" library
// Again, it assumes some in-built functions, such as "sort" or "sqrt"
// Function to calculate the distance between two points
distance(p1, p2) => {
sum = 0
for i in 0 .. len(p1) - 1 {
sum = sum + (p1[i] - p2[i]) ^ 2
}
sqrt(sum)
}
// Function to find the k nearest neighbors
k_nearest_neighbors(data, point, k) => {
distances = data | > map(p => (p, distance(p, point)))
distances | > sort((a, b) => a[ 1 ] < b[ 1 ]) | > take(k) | > map(p => p[ 0 ])
}
Una de las características interesantes de los idiomas funcionales es que pueden ser altamente expresivos. Aquí, solicité a ChatGPT a implementar el map , filter y reduce (o doblar los operadores funcionales básicos (o fold en el contexto de lenguajes funcionales). Para los primeros casos, el modelo parecía perder el rastro de los aspectos funcionales de SIL, pero podría volver a implementar el código de una manera más funcional cuando se le solicite.
// map
map(fn, list) => {
result = []
for i in list {
result.append(fn(i))
}
return result
}
// filter
filter(fn, list) => {
result = []
for i in list {
if (fn(i)) {
result.append(i)
}
}
return result
}
// reduce
reduce(fn, list, initial) => {
result = initial
for i in list {
result = fn(result, i)
}
return result
}
// reduce (prompted to use functional operators such as pipe |>, in addition to the 'map' and 'filter' functions defined previously)
reduce(fn, list, initial) =>
list | >
filter(fn, _, initial) =>
map(fn, _, initial) =>
initialProject Euler es una colección de problemas matemáticos y de programación (que creo que hacen indicaciones interesantes para los LLM). Aquí, solicito a ChatGPT a resolver los dos primeros problemas de Euler del proyecto usando SIL. En este punto, los representantes de Chatgpt se dieron un poco; Ninguna de estas soluciones se parece mucho a la funcionalidad de alto nivel de SIL ni su sintaxis exAXCT. Puede ser interesante proporcionar más ejemplos de código SIL en este momento y luego volver a practicar el modelo para resolver estos problemas.
// Project Euler problem #1:
// Here, my prompt was to solve the (easy) first problem of the Project Euler series (https://projecteuler.net/problem=1)
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
result = 0
for i in 1 ... 1000 {
if (i % 3 == 0 || i % 5 == 0 ) {
result += i
}
}
print(result) // Project Euler problem #2:
// This prompt is to solve the second Project Euler problem (https://projecteuler.net/problem=2)
// The solution proposed by ChatGPT is sensible, but potentially inefficient, and ignores the recursion of functional languages
// Notably, despite if/else statements featuring in the code prompts used for training, ChatGPT gets the syntax wrong here
result = 0
fib(n) => {
if (n <= 1 ) {
return n
}
return fib (n - 1 ) + fib(n - 2 )
}
for i in 1 ... 100 {
val = fib(i)
if (val > 4000000 ) {
break
}
if (val % 2 == 0 ) {
result += val
}
}
print(result)
Explorar la capacidad de los LLM para inferir y comprender las características de un lenguaje de programación novedoso de una manera de pocos disparos sigue siendo una pregunta abierta e interesante. Aquí, estas capacidades se exploraron en el contexto de pedir a ChatGPT a resolver problemas provocados en un nuevo lenguaje específico de dominio (DSL) llamado SIL. Los DSL son un caso de prueba potencialmente útil para explorar la inferencia frente a la memorización en LLMS, ya que a menudo tienen características distintivas y es menos probable que se hayan encontrado ampliamente durante el entrenamiento (si es que lo hace).
En general, el rendimiento se mezcló: ChatGPT entendió correctamente que este DSL es un lenguaje de programación funcional (aunque a veces tuvo que volver a prometirse de esto) e implementó sus soluciones en consecuencia. Sin embargo, no pudo capturar las reglas sintácticas de este DSL de los cinco scripts de ejemplo proporcionados. Investigaciones adicionales (como el uso de otros DSL, desarrollar algunas métricas más formales para evaluar el código generado por LLM o cuantificar la dinámica de aprendizaje del modelo) sería una extensión intrigante de este repositorio. Finalmente, en una sesión de chatgpt separada, proporcioné este meta-prompt para determinar cómo el modelo interpretó su propio código SIL:

ChatGPT examina su propio intento de escribir código en el lenguaje específico del dominio SIL, y describe algunas de sus características.
Existe evidencia de que la memorización de LLM es promovida por la frecuencia de la presentación de ejemplo de entrenamiento y el número de tokens relevantes utilizados para impulsar el modelo. ↩