Diario
Secciones
Ajustes de lectura
Ninguna voz para este idioma en este navegador.
Más voces
Código y términos técnicos en inglés
Desactivado: la voz de la página lo lee todo, sin pausa entre dos voces.
Ninguna voz para este idioma en este navegador.
Más voces
Más voces: Microsoft Edge ofrece voces naturales en línea, y Windows (Configuración › Hora e idioma › Voz), macOS y Android instalan otras.
Progreso
Sección titulada «Progreso»- Código del curso: scripts, sesiones de F# Interactive, fragmentos rechazados, soluciones de los ejercicios y tres proyectos pequeños, comparados con su salida esperada por
check.sh - CI en Linux, Windows y macOS: subida, en verde el 2026-09-16, en rojo desde el 2026-09-20 por tres archivos esperados (ver el 2026-09-22)
- Lección 1: scripts, F# Interactive y proyectos
- Lección 2: valores, funciones e inferencia de tipos
- Lección 3: tuplas, records, uniones y opciones
- Lección 4: coincidencia de patrones
- Lección 5: listas, arrays y secuencias
- Lección 6: módulos, espacios de nombres y organización del proyecto
- Lección 7: errores con
Result - Lección 8: expresiones de cómputo aplicadas al parsing de un DSL
- Lección 14: proveedores CSV y JSON con FSharp.Data 8.2.0
El SDK de .NET 10 (10.0.112), F# 10 y dotnet fsi 14.0.112.0; TARS en 87464ce y GuitarAlchemist/ga en 32f143c para los casos prácticos. La primera fila es del propio curso: es la razón por la que la CI está en rojo desde el 2026-09-20. Nada se ha reportado aguas arriba. La tabla de experimentos que sigue no cambia.
| Esperado | Lo que pasa | Dónde | Medición | Estado |
|---|---|---|---|---|
| Las salidas esperadas subidas con las lecciones 5 a 8 son lo que imprimen los ejemplos | Tres de ellas terminan con una línea en blanco más de lo que imprimen los ejemplos, y la CI falla en los tres sistemas | code/fsharp/expected/l05_collections.txt, l06_modules.txt, l07_result.txt, commit 69a02c4 |
FAIL l05_collections, FAIL l06_modules, FAIL l07_result en cada sistema en la ejecución 35528402823; los archivos terminan en exit 0 seguido de dos saltos de línea |
Reproducido; diagnosticado, aún no corregido 2026-09-22 |
Un script se ejecuta de arriba abajo, así que un printfn antes de un error se imprime |
Todo el script se comprueba primero, así que no se imprime nada | l01_format_type.fsx, dotnet fsi 14.0.112.0, F# 10.0 |
El printfn sobre el error no imprime nada |
Por diseño 2026-09-15 |
| Un compilador señala en una pasada todos los errores independientes de un archivo | F# Interactive señala uno por ejecución | F# Interactive 14.0.112.0, ejercicio 3 de la lección 2 | Tres errores independientes necesitan cuatro ejecuciones | Reproducido; si dotnet build los agrupa sigue por verificar 2026-09-15 |
dotnet fsi y dotnet build presentan un diagnóstico igual |
fsi imprime el nombre de archivo a secas; dotnet build imprime la ruta completa, añade [project.fsproj], imprime cada error dos veces y deja espacios finales en el texto de FS0001 |
SDK 10.0.112 | El mismo error, dos formas | Reproducido; check.sh quita la ruta, el sufijo, los duplicados y los espacios finales 2026-09-15 |
| Una igualdad usada como sentencia avisa dondequiera que aparezca | strings = 7 produce FS0020 dentro de una función y nada en el nivel superior de un script |
dotnet fsi, SDK 10.0.112 |
FS0020 dentro de una función; ningún aviso en el nivel superior | Reproducido, no reportado 2026-09-15 |
| Un tabulador es espacio en blanco, así que el código sangrado con tabuladores compila | El compilador lo rechaza | F# Interactive, SDK 10.0.112 | error FS1161: TABs are not allowed in F# code unless the #indent "off" option is used |
Por diseño 2026-09-15 |
Un switch de C# con una rama por subclase sealed de un abstract record es exhaustivo |
Roslyn avisa igualmente; el programa compila y se ejecuta | hierarchy.cs(3,42), SDK 10.0.112 |
warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). |
Por diseño: C# no tiene jerarquías cerradas, y eso es lo que muestra la comparación 2026-09-15 |
Un switch de C# sobre los tres valores con nombre de un enum es exhaustivo |
Roslyn avisa de un valor sin nombre fuera del conjunto declarado | enumswitch.cs(3,41), SDK 10.0.112 |
warning CS8524: … For example, the pattern '(Accidental)3' is not covered. |
Por diseño 2026-09-15 |
Los archivos .fs del árbol de fuentes activo los compila algún proyecto |
Nueve archivos .fs de v2/src no están en ningún .fsproj, y un proyecto falta en la solución, así que la CI nunca lo construye |
GuitarAlchemist/tars en 87464ce, v2/src; Tars.LSP.fsproj ausente de v2/Tars.sln |
Fibonacci.fs, LintRunner.fs, OllamaClient.fs, ToolFactory.fs y cinco más; dos miden 95 y 3 bytes |
Reproducido; usado en la lección 1 2026-09-15 |
La insignia «License: MIT» del README enlaza a un archivo LICENSE |
No hay archivo LICENSE en ese commit |
GuitarAlchemist/tars en 87464ce, el enlace del README a ./LICENSE |
Un enlace roto | Reproducido, no reportado 2026-09-15 |
Un Error a secas en F# significa Result.Error |
Dos uniones declaradas sin [<RequireQualifiedAccess>] lo ocultan, y cada archivo posterior debe cualificarlo |
Domain.fs, líneas 62-78 |
342 apariciones de Result.Error en v2/src; ArcTypes.fs llega a escribir FSharp.Core.Result.Error |
Reproducido en compile_fail/l03_case_shadowing.fsx y mostrado en la lección 3; corregirlo aguas arriba rompería la API 2026-09-15 |
| Un normalizador de texto conserva los caracteres significativos de su entrada | Su patrón [^a-z0-9\s] quita # y todas las letras con tilde, y ningún test cubre ninguno de los dos |
TextNormalizer.fs, líneas 51-58 |
"learn F#" da las palabras clave learn y f; café da caf |
Reproducido; mostrado en la lección 2 2026-09-15 |
| Un tipo documentado como seguro entre hilos lee su estado mutable bajo su cerrojo | Remaining toma el cerrojo; la propiedad Consumed devuelve el campo mutable consumed sin él |
Budget.fs, líneas 133-150, BudgetGovernor |
Leído en el código | No reproducido: esta fila es una lectura de código. Reservado para la lección 16 2026-09-15 |
Un analizador que devuelve Ok consumió toda su entrada |
pChord no va seguido de eof, así que se detiene en el primer carácter que no conoce y devuelve Ok para el prefijo |
GuitarAlchemist/ga en 32f143c, ChordParser.parse, heredado por ChordDslService y por el ResponseValidator del chatbot |
C7sus4 se lee como C7; Am(maj7) como Am |
Reproducido en examples/l04_ga_parse.fsx y mostrado en la lección 4 2026-09-15. Corregido upstream por #682 y #689, fusionadas el 2026-09-23: sobre 27a1257, C7sus4 se analiza con los componentes 7 y sus4, y Am(maj7) es un error en la columna 3 2026-09-24 |
| La forma normal no depende de la transposición | List.minBy fst se queda con la primera rotación de igual amplitud en vez de comparar los intervalos interiores, y la respuesta se mueve con la transposición |
GuitarAlchemist/ga en 32f143c, HarmonicTransformationService.GetNormalForm |
{0, 4, 7, 8} da [0; 4; 7; 8]; el mismo conjunto transpuesto 8 da [0; 3; 4; 8] |
Reproducido en examples/l02_ga_transformations.fsx; no se encontró ningún llamador, y ningún test lo cubre 2026-09-15. HarmonicTransformationService.fs no cambió en 27a1257 2026-09-24. Corregido por #734, fusionada el 2026-09-24, con el desempate de Rahn 2026-09-24 |
Experimentos
Sección titulada «Experimentos»| Pregunta | Hipótesis | Resultado medido | Veredicto | Evidencia |
|---|---|---|---|---|
| ¿Una expresión de cómputo mínima hace legible la gramática de un DSL sin ocultar errores? | Bind y Return bastan para la gramática secuencial de notas. |
Pasan cuatro casos, incluido el rechazo de una letra inválida y de texto sobrante. | Confirmada | Entrada de 2026-09-20, l08_parser_ce.fsx |
| ¿FSharp.Data infiere miembros CSV y JSON anidados útiles en .NET 10? | FSharp.Data 8.2.0 expondrá columnas y propiedades tipadas en F# 10. | Dos filas CSV y un documento JSON anidado compilan e imprimen los valores esperados. | Confirmada | Entrada de 2026-09-20, l14_type_providers.fsx |
2026-09-15 — El SDK y F# Interactive
Sección titulada «2026-09-15 — El SDK y F# Interactive»- Mi máquina tiene los SDK de .NET 10.0.112 y 11.0.100-preview.3.26207.106. El
global.jsondel curso fija10.0.100conrollForward: latestFeature, lo que selecciona 10.0.112: F# Interactive 14.0.112.0 para F# 10.0, y FSharp.Core con la versión de ensamblado 10.0.0.0. - Los ejemplos son scripts
.fsxejecutados condotnet fsi, en lugar de proyectos: un script arranca en unos 2 segundos en mi máquina, no necesita compilación y puede cargar los archivos de GA con#loady referenciar FParsec con#r "nuget: …". Solo la lección 1 compila proyectos, tres pequeños, cada uno en unos 2 segundos. - Un script se comprueba entero antes de ejecutarse: en
l01_format_type.fsx, elprintfnque está por encima del error no imprime nada. - F# Interactive señaló un error por ejecución en los scripts de este lote: el ejercicio 3 de la lección 2 tiene tres errores independientes y necesita cuatro ejecuciones. No he comprobado si
dotnet buildseñala varios a la vez en un proyecto. - Los mensajes del compilador de un script muestran el nombre del archivo sin su carpeta, incluso cuando el script se ejecuta desde otra carpeta.
dotnet buildmuestra la ruta completa, añade[project.fsproj]e imprime cada error dos veces (una cuando ocurre y otra en el resumen):check.shconserva las líneaserror FS/warning FS, quita la ruta y el sufijo, y elimina los duplicados. Los mensajes de varias líneas, como el «expected to have type» de FS0001, terminan algunas líneas con espacios, quecheck.shtambién quita. - Una excepción no controlada en un script imprime la pila de llamadas con rutas completas, luego
Stopped due to error, ydotnet fsisale con el código 1.check.shelimina las líneasat …. - Las sesiones de F# Interactive se comprueban enviando un archivo a
dotnet fsi --nologo: la salida contiene los indicadores>y las respuestas, sin las líneas escritas. Las lecciones muestran la entrada junto a las respuestas, como las ve una persona. - Una igualdad usada como instrucción (
strings = 7) recibe la advertencia FS0020 dentro de una función, pero ninguna advertencia en el nivel superior de un script: lo probé fuera del código del curso, y la lección 2 solo muestra la función. - La indentación con una tabulación se rechaza:
error FS1161: TABs are not allowed in F# code unless the #indent "off" option is used(probado fuera del código del curso). - Una comprobación en C# detrás de la lección 4, compilada aparte con el SDK 10.0.112: ver 2026-09-15 — Comparaciones con C#.
2026-09-15 — CI
Sección titulada «2026-09-15 — CI»- El workflow
.github/workflows/fsharp-examples.ymlejecutacheck.shenubuntu-latest,windows-latestymacos-latest, como los demás cursos. No se ha subido: el token con el que se sube este repositorio no puede crear archivos de workflow (le falta el ámbitoworkflow). Mientras tanto, las salidas solo se han comprobado en Windows, y todo lo específico de Linux y macOS está marcado por verificar. - Dos salidas contienen caracteres no ASCII:
EbΔ9y las comillas‘…’de FParsec enl04_ga_parse. Son correctos en Git Bash en mi máquina; el runner de Windows podría imprimirlos con otra codificación (por verificar).
2026-09-15 — Dogfooding: TARS
Sección titulada «2026-09-15 — Dogfooding: TARS»TARS en el commit 87464ce.
- Lo que está activo. El README dice que todo el desarrollo activo está en
v2/. El workflow de CIdotnet.ymlrestaura, compila y prueba solov2, yv2/Tars.slncontiene 17 proyectos bajov2/srcy un proyecto de pruebas. El nivel superior del repositorio conserva decenas de carpetas más antiguas (TarsEngine.FSharp.*,backup_fake_elimination_*…) que ningún workflow compila: las lecciones no las citan. - Nueve archivos
.fsque nada compila. El propiov2/srccontieneFibonacci.fs,FSharp.ReverseList.fs,LintRunner.fs,Main.fs,OllamaClient.fs,PalindromeChecker.fs,Program.fs,StaticAnalysisRunner.fsyToolFactory.fs. Ningún.fsprojlos lista (los proyectos con los mismos nombres de archivo listan sus propias copias, comoTars.Llm/OllamaClient.fs), y dos de ellos están casi vacíos (95 y 3 bytes).v2/src/Tars.LSPtiene un proyecto,Tars.LSP.fsproj, queTars.slnno incluye, así que la CI tampoco lo compila. La lección 1 lo usa para mostrar que un proyecto F# solo compila los archivos que lista. - Sin archivo de licencia. El README muestra una insignia «License: MIT» que enlaza a
./LICENSE, pero el repositorio no tiene archivoLICENSEen este commit, así que el enlace está roto. El curso enlaza y cita el código de TARS pero no copia sus archivos;examples/l02_tars_normalize.fsxvuelve a escribir una función de ocho líneas para ejecutarla. - Casos de unión que ocultan
Result.Domain.fsdeclaraPartialFailure.ErroryExecutionOutcome.Failuresin[<RequireQualifiedAccess>]. Cada archivo compilado después que quiere decirResult.Errordebe calificarlo:v2/srctiene 342 apariciones deResult.Error, yArcTypes.fsescribeFSharp.Core.Result.Error. Los archivos compilados antes, comoBudget.fs, escriben un simpleError. Añadir el atributo rompería código dentro de TARS (cadaWarning,Error,Success,Failurede estas uniones necesitaría el nombre de su tipo). Reproducido encompile_fail/l03_case_shadowing.fsx; se muestra en la lección 3. TextNormalizer.normalizesolo conserva ASCII. La expresión regular[^a-z0-9\s]deTextNormalizer.fselimina#("learn F#"da las palabras clavelearnyf) y todas las letras acentuadas (cafédacaf). Sus pruebas solo usan frases en inglés, y no encontré ningún llamador env2/srcaparte de sus pruebas (grepen este commit). Se muestra en la lección 2.- Para la lección 16:
BudgetGovernorenBudget.fsse declara seguro para hilos y lee sumutable consumedcon un bloqueo enRemaining, pero su propiedadConsumeddevuelve el campo sin el bloqueo.
2026-09-15 — Dogfooding: Guitar Alchemist
Sección titulada «2026-09-15 — Dogfooding: Guitar Alchemist»GA en el commit 32f143c. Seis archivos están copiados en code/fsharp/external/ga, sin cambios salvo sus finales de línea.
ChordParser.parsedescarta el final de la entrada.pChordno va seguido deeof, así que el parser se detiene en el primer carácter que no reconoce y devuelveOkcon lo que ha leído:C7sus4se normaliza aC7, yAm(maj7)aAm(examples/l04_ga_parse.fsx, lección 4).ChordDslService.ParseyNormalizelo heredan, y elResponseValidatoren C# del chatbot, que solo comprueba siParsetuvo éxito, acepta cualquier palabra que empiece como un acorde y coincida con su expresión regular. Un posible arreglo esrun (pChord .>> eof) chordStr, añadiendoC7sus4yAm(maj7)aChordDslTests.cs; unsus4real después de una extensión necesitaría entonces también una regla del parser.HarmonicTransformationService.GetNormalFormdepende de la transposición. Para el conjunto{0, 4, 7, 8}devuelve[0; 4; 7; 8], y para el mismo conjunto transpuesto 8 semitonos devuelve[0; 3; 4; 8]: dos rotaciones tienen la misma extensión, yList.minBy fstse queda con la primera en lugar de comparar los intervalos interiores como hace el orden normal (examples/l02_ga_transformations.fsx, lección 2). La búsqueda de código de GitHub no encontró ningún llamador deGetNormalFormen GA el 2026-09-15, y elHarmonicTransformationTests.csde GA no la prueba. En el mismo archivo,InvertyApplyNegativeHarmonycalculan la misma fórmula (2 * axis - pcysumAxis - pc), y el comentario deApplyNegativeHarmonytodavía pregunta «axis = 3.5 semitones?».Scripts/BinObj.fsxselecciona de más y no ejecuta nada.isObjOrBinFoldercomprueba si una ruta completa termina enbinuobj, sin distinguir mayúsculas, así que se seleccionan carpetas llamadascabinoRobin, y sus subcarpetas no se visitan. El script define sus funciones y nunca las llama (examples/l04_ga_binobj.fsx, lección 4).Scripts/ModesConfig.fsxno se ejecuta. Ejecutado tal cual condotnet fsidesde la carpetaScripts, se detiene en la línea 21 con doserror FS3373: Invalid interpolated string(en las columnas 57 y 59): un literal de cadena", "dentro de una interpolación$"…". Con una cadena entre comillas triples, la misma línea recibeFS0039: The value, constructor, namespace or type 'Join' is not defined, ya que el script no tieneopen System(reproducido en el ejercicio 2 de la lección 1). Además,#r "nuget: GA.Business.Config, 1.0.0"nombra un paquete que nuget.org no tiene (su índice de paquetes respondióBlobNotFoundel 2026-09-15), y#Iañade una carpeta donde buscar ensamblados, no un origen de paquetes. Existe otroModesConfig.fsxen la raíz del repositorio.- Dos árboles para un acorde.
ChordAstpuede escribirBbmaj7comoQuality = NoneconExtension "maj7"(lo que produce el parser) o comoQuality = Some MajorconExtension "7"; ambos se renderizan con el mismo texto y se comparan como distintos (ejercicio 3 de la lección 3).
2026-09-15 — Comparaciones con C#
Sección titulada «2026-09-15 — Comparaciones con C#»La lección 4 compara la comprobación de exhaustividad de F# con la de C#. Los dos archivos C# de abajo se compilaron aparte con dotnet run y el SDK 10.0.112, no en la CI del curso:
-
Una jerarquía de records
abstract record Fingeringcon tres subclasessealed, y una expresiónswitchcon un brazo por subclase:hierarchy.cs(3,42): warning CS8509: The switch expression does not handle all possible values of its input type (it is not exhaustive). For example, the pattern '_' is not covered. -
Un
enum Accidental { Natural, Sharp, Flat }y una expresiónswitchcon un brazo por valor con nombre:enumswitch.cs(3,41): warning CS8524: The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. For example, the pattern '(Accidental)3' is not covered.
Los dos programas se ejecutaron igualmente e imprimieron su resultado.
2026-09-20 — Colecciones, módulos y Result
Sección titulada «2026-09-20 — Colecciones, módulos y Result»- Se añadió la lección 5 con comparaciones ejecutables entre las transformaciones inmediatas de
ListyArrayy un pipelineSeqperezoso. - Se añadió la lección 6 con módulos anidados, visibilidad explícita y un ejemplo pequeño de organización que mantiene estrecha la superficie pública.
- Se añadió la lección 7 con un pipeline de validación basado en
Result, composición explícita de errores y la frontera entre fallos esperados y excepciones. dotnet fsireprodujo las salidas guardadas paral05_collections.fsx,l06_modules.fsxyl07_result.fsxcon el SDK .NET 10.0.112.
2026-09-20 — Expresiones de cómputo y proveedores de tipos
Sección titulada «2026-09-20 — Expresiones de cómputo y proveedores de tipos»- Se añadió la lección 8 en torno a un builder real
Parser<'T>. El harness ejecuta casos de éxito, token inválido y texto sobrante; este último mantiene explícito el invariante de final de entrada. - Se añadió la lección 14 con FSharp.Data 8.2.0, fijado desde NuGet. Las muestras CSV y JSON son strings locales, por lo que el tipado no depende de un esquema remoto.
dotnet fsiprodujo las salidas guardadas enexpected/l08_parser_ce.txtyexpected/l14_type_providers.txtcon el SDK .NET 10.0.112.
2026-09-22 — CI en tres sistemas
Sección titulada «2026-09-22 — CI en tres sistemas»- La entrada del 2026-09-15 dice que el workflow no se ha subido. Se subió después: la ejecución 35097250880, el 2026-09-16, pasó en
ubuntu-latest,windows-latestymacos-latest. - La ejecución 35528402823, el 2026-09-20, la primera tras las lecciones 5 a 8 y 14, falló en los tres. Casi todo su log son líneas
ok, lo que la hacía parecer un fallo sin comprobación fallida. La hay:FAIL l05_collections,FAIL l06_modulesyFAIL l07_result, una vez por sistema, cada una seguida de undiffque quita una línea vacía al final. Los tres archivos esperados terminan enexit 0y dos saltos de línea; los demás archivos esperados, en uno.check.shponestatus=1ante cada diferencia y sigue, así que todas las comprobaciones posteriores imprimenoky el script sale con 1 al final. El diagnóstico es de auggie, comprobado contra el log y los archivos; no se sabe cómo entraron esas líneas de más en el commit. - La corrección es quitar un salto de línea final en cada uno de los tres archivos. Aún no está aplicada.
- La misma ejecución resuelve dos notas por verificar:
l04_ga_parse, conEbΔ9y las comillas‘…’de FParsec, imprimeoken el runner de Windows, y cada lección imprime la misma salida en Linux, macOS y Windows salvo esos tres archivos.
2026-09-24 — Correcciones upstream comprobadas de nuevo
Sección titulada «2026-09-24 — Correcciones upstream comprobadas de nuevo»ChordParser.parseexige ahora el símbolo entero (#682) y lee7sus4,Maj7yomit(#689), ambas fusionadas el 2026-09-23. Relanzado sobre GA27a1257con elrecheck/probe.csde music-theory-ga:C7sus4→OkconComponents = [Extension "7"; Extension "sus4"], yAm(maj7)→Error in Ln: 1 Col: 3. La lección 4 sigue fijada a32f143cy sigue mostrando el prefijo aceptado.GetNormalFormno cambió: su archivo es idéntico en32f143cy en27a1257.- #734, fusionada el 2026-09-24, corrige
GetNormalForm: los empates de amplitud se resuelven como lo hace Rahn, por los intervalos del primer elemento al penúltimo, luego al antepenúltimo, y así sucesivamente.{0, 4, 7, 8}da ahora[0; 3; 4; 8], igual que su transposición por 8. Su prueba pasa los 4.096 conjuntos por T1 a T11; con el código antiguo, 5.920 de esas 45.045 transposiciones cambiaban la respuesta. El comentario de documentación ya no llama al resultado una forma prima de Forte: es el orden normal transpuesto a cero, sin la inversión. Una última prueba fija{0, 1, 5, 6, 8}, un conjunto en el que Rahn y Forte no coinciden.
Por verificar
Sección titulada «Por verificar»- Las carpetas de salida de la compilación de la lección 1 en Linux y macOS (ejecutable
Hello, carpetas de recursos). - Alt+Enter para enviar código a F# Interactive en VS Code con Ionide, Rider y Visual Studio.
- Si
dotnet buildseñala en una sola ejecución varios errores independientes de un mismo archivo, donde F# Interactive señaló uno.