[NB: um acompanhamento deste repo usando o GPT-4 pode ser encontrado aqui.]
Modelos de grandes idiomas (LLMs), como ChatGPT e Claude, demonstraram habilidades impressionantes de programação e são capazes de resolver problemas em uma ampla gama de idiomas e suas taxonomias. Apesar desses sucessos, algum ceticismo persiste na medida em que esses modelos exibem qualquer apreciação subjacente das regras sintáticas e operacionais subjacentes a esses idiomas ( versus memorização dos padrões dos dados de treinamento).
Neste repositório de engenharia rápida, as habilidades de programação do ChatGPT são exploradas usando uma linguagem específica de domínio arbitrária (DSL). As DSLs representam um substrato atraente para o estudo das capacidades de inferência do LLMS porque são novas e menos propensas a ter sido extensivamente encontradas e memorizadas durante o treinamento 1 . Como tal, eles permitem um teste mais direto da extensão em que os LLMs podem inferir as regras de novas linguagens de programação de alguma maneira .
Aqui, a linguagem específica do domínio SIL (linguagem de integração de simetria) foi selecionada por dois motivos. Em primeiro lugar, é extremamente improvável que o ChatGPT tenha sido exposto a qualquer código SIL durante o treinamento, pois é um DSL interno desenvolvido por um fundo de hedge pesado de tecnologia chamado Symmetry Investments. Em segundo lugar, como uma linguagem de programação, possui alguns recursos interessantes para o modelo reproduzir (por exemplo, é uma linguagem funcional que enfatiza a expressividade, mas carece let expressões como em Haskell ou OCAML).

Após alguns exemplos de código, o ChatGPT tenta escrever código em um romance, DSL funcional conhecido como 'SIL'.
Abaixo está uma coleção de avisos que consistem em breves exemplos de código SIL que destacam sua funcionalidade. Depois de solicitar o ChatGPT com a tarefa e fornecer amostras de código SIL (veja a figura abaixo; histórico completo e exemplos de código SIL também estão nesse repositório), pedi para implementar várias tarefas de programação convencionais no SIL.
Nas seções abaixo, mostro alguns dos scripts de código SIL com os quais o modelo foi solicitado (o conjunto completo de exemplos pode ser encontrado aqui) e suas tentativas de implementar vários problemas no SIL.
O primeiro prompt é um script para lidar com algumas funcionalidades do servidor de email. Como tal, ele difere muito do tipo de problema que levarei posteriormente o ChatGPT a resolver, mas ilustra algumas das sintaxe, estruturas de dados e aspectos funcionais do SIL (por exemplo |> ).
// 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]) O Segundo Exemplo de Código Prompt de mesma forma pretende destacar alguns recursos deste DSL para o modelo e apresenta algumas novas funções de biblioteca padrão, como iota e 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)A terceira amostra de código ilustra ainda alguns dos recursos incomuns deste DSL, com o objetivo de que o ChatGPT os usará em suas próprias implementações a seguir.
// 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 primeiro exercício, pedi ao modelo para implementar um banco de dados relacional muito simples no SIL, com funcionalidades básicas, como comparar e imprimir a diferença entre duas estrutura de dados (observe que // indica comentários no 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]"}]A implementação de algoritmos de classificação é uma pergunta de entrevista de engenharia de software arquetípica. Aqui, pedi ao ChatGPT que implemente o Bubblesort (conceitualmente o algoritmo de classificação mais básico) no SIL. Abaixo está a resposta:
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)) Embora esse script seja, de fato, uma implementação de funcionamento do Bubblesort, o modelo ignora amplamente os aspectos funcionais do SIL. Por exemplo, essa implementação do BubbleSort for loops em vez de recursão.
Em seguida, levei o modelo a escrever um script para calcular a mediana de uma lista (resposta gerada abaixo). Essa foi, talvez, uma das respostas menos satisfatórias. Em primeiro lugar, apesar das instruções if/else apresentando no exemplo do código SIL com o qual eu solicitei o modelo, a sintaxe neste código gerado está incorreto. Em segundo lugar, o chatgpt alucina (ou assume) a presença de um módulo chamado math e uma sort função Buil-in (essas são suposições razoáveis, mas diminui significativamente a complexidade do problema solicitado).
// 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
}
O ChatGPT foi solicitado a implementar o algoritmo K -Nearest Neighbours em SIL. Na verdade, esse é o resultado de dois avisos (conforme descrito no bloco de código gerado abaixo), porque o modelo alucina/assume um módulo chamado distances na primeira tentativa. Na segunda tentativa, solicitei implementar o algoritmo sem assumir a existência deste módulo.
O desempenho do ChatGPT aqui está misto. Em primeiro lugar, em alguns casos, ignora os aspectos funcionais do SIL (como a implementação for um loop para a primeira tentativa. Em outras partes da implementação, no entanto, aprecia que o SIL é funcional e emprega |> operadores map com precisão. No momento, o modelo é que o modelo é que o modelo é let o código é que o código é que o código é que o código é que o código é que o código é provável.
// 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 ])
}
Uma das características interessantes das linguagens funcionais é que elas podem ser altamente expressivas. Aqui, solicitei que o ChatGPT implemente o map básico de operadores funcionais, filter e reduce (ou fold no contexto de linguagens funcionais). Nos primeiros casos, o modelo parecia perder o controle dos aspectos funcionais do SIL, mas poderia implementar o código de uma maneira mais funcional quando solicitado.
// 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) =>
initialO Project Euler é uma coleção de problemas matemáticos e de programação (que acho que fazem avisos interessantes para o LLMS). Aqui, eu solicito a Chatgpt a resolver os dois primeiros problemas do projeto Euler usando o SIL. Neste ponto, os repsenses de Chatgpt se interromperam um pouco; Nenhuma dessas soluções tem muita semelhança com a funcionalidade de alto nível de SIL nem sua sintaxe exaxct. Pode ser interessante fornecer outros exemplos de código SIL neste momento e depois promover o modelo para resolver esses 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 a capacidade dos LLMs de inferir e entender as características de uma nova linguagem de programação de alguma maneira permanece uma pergunta aberta e interessante. Aqui, essas capacidades foram exploradas no contexto de solicitar o ChatGPT a resolver os problemas provocados em uma nova linguagem específica de domínio (DSL) chamada SIL. As DSLs são um caso de teste potencialmente útil para explorar a inferência versus memorização no LLMS, pois geralmente têm características distintas e são menos propensas a ter sido extensivamente encontradas durante o treinamento (se houver).
No geral, o desempenho foi misto: o chatgpt entendeu corretamente que esse DSL é uma linguagem de programação funcional (embora às vezes tivesse que ser re-interpretada disso) e implementou suas soluções de acordo. No entanto, ele não conseguiu capturar as regras sintáticas deste DSL dos cinco scripts de exemplo fornecidos. Investigações adicionais (como o uso de outras DSLs, o desenvolvimento de uma métrica mais formal para avaliar o código gerado por LLM ou quantificar a dinâmica de aprendizado do modelo) proporcionaria uma extensão intrigante desse repositório. Finalmente, em uma sessão de ChatGPT separada, forneci essa meta-promoção para determinar como o modelo interpretou seu próprio código SIL:

O ChatGPT examina sua própria tentativa de escrever código na linguagem específica do domínio SIL e descreve alguns de seus recursos.
Há evidências de que a memorização do LLM é promovida pela frequência de apresentação de exemplo de treinamento e pelo número de tokens relevantes usados para solicitar o modelo. ↩