¿Hay algo inherentemente diferente en el diseño o la ideología de F # que está causando esto?
Sí. F # usa el tipado nominal en lugar del estructural porque es más simple y, por lo tanto, más fácil de usar por simples mortales.
consideran este F # ejemplo:
let lengths (xss: _ [] []) = Array.map (fun xs -> xs.Length) xss
let lengths (xss: _ [] []) = xss |> Array.map (fun xs -> xs.Length)
El primero no se compila porque el tipo de xs
dentro de la función anónima no puede deducirse porque F # no puede expresar el tipo "alguna clase con un miembro de Length
".
En contraste, OCaml puede expresar el equivalente directo:
let lengths xss = Array.map (fun xs -> xs#length) xss
porque OCaml puede expresar ese tipo (que está escrito <length: 'a ..>
). Tenga en cuenta que esto requiere una inferencia de tipo más poderosa que la que tienen actualmente F # o Haskell, p. OCaml puede inferir tipos de suma.
Sin embargo, se sabe que esta característica es un problema de usabilidad. Por ejemplo, si se equivoca en otro lugar del código, entonces el compilador todavía no ha deducido que se suponía que el tipo de xs
era una matriz, por lo que cualquier mensaje de error que pueda proporcionar solo puede proporcionar información como "algún tipo con un miembro de longitud" y no "una matriz". Con solo un código un poco más complicado, esto rápidamente se sale de control ya que tiene tipos masivos con muchos miembros estructuralmente inferidos que no se unifican del todo, lo que lleva a mensajes de error incomprensibles (como C++/STL).
De hecho, me desagrada la pregunta, pero ya se han obtenido algunas respuestas fantásticas y esclarecedoras, así que también envidié a regañadientes :) – Brian
@J Cooper: "Haskell (por ejemplo) no tiene tales limitaciones con una inferencia igualmente poderosa". Haskell no está cerca de tener una inferencia de tipo igualmente poderosa cuando se consideran las impurezas o el rendimiento. Por ejemplo, la función 'piso 'de Haskell típicamente ejecuta órdenes de magnitud más lentas que cualquier otro lenguaje compilado precisamente porque su falla al inferir el tipo estático correcto lo deja recurriendo al despacho en tiempo de ejecución. Además, si dejo de eliminar la anotación de tipo de nivel superior de una función 'randIntList' que tengo aquí, entonces deja de compilar con el infame error' ambiguous type variable'. –
Me gusta la pregunta porque supongo que casi todos los que acaban de comenzar a aprender F # tienen dos pensamientos: "¡WOW, F # es tan poderoso!" y "WTF, ¿por qué F # no puede hacer esta inferencia tonta?" :) –