2010-11-30 22 views
6

Me preguntaba si hay algún lenguaje agradable que ofrezca algún tipo de abstracción para "pies" frente a "pulgadas" o "cm" etc. Estaba considerando hacer algo como lo siguiente en Java:preservando unidades para cálculos en la programación

u(56).feet() + u(26).inches() 

y ser capaz de conseguir algo como

17.7292 metros como el resultado.

Un posible enfoque es, al crear un nuevo valor, convertirlo inmediatamente en una unidad "base", como metros o algo así, para que pueda agregarlos fácilmente.

Sin embargo, yo preferiría tener la capacidad de preservar unidades, por lo que algo como

u(799.95555).feet() - u(76).feet() 

vuelve

723.95555 feet 

y no

243.826452 meters - 23.1648 meters = 220.661652 meters 

//220.661652 meters to feet returns 723.955551 feet 

Desde este problema parece sería muy común, ¿existe algún marco o incluso un lenguaje de programación que maneje esto elegantemente?

Supongo que puedo simplemente agregar las unidades como están en mis métodos, agregando unidades coincidentes y solo convirtiendo para +-*/ [agregar/restar/multiplicar/dividir] cuando se soliciten, lo cual es genial para agregar y restar:

//A 
{ 
    this.inches = 36.2; 
    this.meters = 1; 
} 

//total length is 1.91948 m 

si añado esto a un objeto B con valores

//B 
{ 
    this.inches = 0.8; 
    this.meters = 2; 
} 

//total length is 2.02032 m 

y consigo un nuevo objeto que es

{ 
    this.inches = 37; 
    this.meters = 3; 
} 

//total length is 3.9398 meters 

que es totalmente increíble, puedo convertirlo siempre que no quiera ningún problema. Pero las operaciones como la multiplicación fallaría ...

//A * B = 3.87796383 m^2 
{ 
    this.inches = 28.96; 
    this.meters = 2; 
} 

// ...but multiplying piece-wise and then adding 
// gives you 2.01868383 m^2, assuming you make 2m*1m give you 2 m^2. 

Así que todo lo que realmente querían mostrar con ese ejemplo era que

(A1 + A2) * (Z1 + Z2) is not (A1 * Z1) + (A2 * Z2) 

y estoy bastante seguro de que esto significa que uno tiene que convertir en una unidad común si quieren multiplicar o dividir.

El ejemplo fue principalmente para desalentar la respuesta reflexiva, que se suman o restan por partes antes de convertir en el último momento, ya que * y / fallarán.

tl; dr: ¿Hay alguna forma inteligente de conservar unidades en la programación? ¿Hay formas inteligentes de nombrar métodos/rutinas tales que me resulte fácil entender lo que estoy agregando y restando, etc.?

Respuesta

5

Sé con certeza que hay un lenguaje así, aunque yo no lo he usado.
Se llama Frink.

No solo le permite mezclar diferentes unidades para la misma dimensión, sino que también puede operar en varias medidas físicas diferentes. El sample calculations en su sitio es una lectura divertida. Particularmente me gusta el bit Superman.

+1

Frink es increíble. También se puede usar fácilmente desde Java. ¡cualquier diseñador de idiomas que logre convertir una charla en una conferencia seria en una broma de pedo de 30 minutos merece un poco de dinero gratis de StackOverflow! –

0

he hecho mucho trabajo con las unidades y no hay nada integral. Puede encontrar muchas utilidades parciales (creo que hay algunas distribuidas con UNIXes). NIST estaba desarrollando un lenguaje de marcado de unidades, pero ha sido por lo menos una década de cocción.

Para hacer esto correctamente necesita una ontología en la que se definen las unidades y las reglas para la conversión. También debes lidiar con prefijos.

Si se apega a la ciencia física (unidades SI), hay 7 (posiblemente 8) tipos de unidades base y 22 cantidades derivadas nombradas. Pero también hay un número infinito de formas en que se pueden combinar. Por ejemplo, la velocidad de cambio de aceleración es llamada "sacudida" por algunos. En principio, podría tener un número indefinido de derivados.

¿Hay unidades de monedas? etc ...

+0

es increíblemente desafortunado que no haya nada dulce (todavía) = ( – sova

+0

Solo por curiosidad, ¿qué le falta a Frink en su opinión? –

2

Muchos lenguajes funcionales permiten la creación de tipos para este tipo de unidad de conservación. En Haskell:

-- you need GeneralizedNewtypeDeriving to derive Num 
newtype Feet = Feet {unFeet :: Float} deriving (Eq, Show, Num) 
newtype Meters = Meters {unMeters :: Float} deriving (Eq, Show, Num) 

Ahora cada unidad es su propio tipo, y sólo se puede realizar operaciones sobre los valores del mismo tipo:

*Main> let a1 = 1 :: Feet 
*Main> let a2 = 2 :: Feet 
*Main> let a3 = 3 :: Meters 
*Main> a1+a2 
Feet 3.0 
*Main> a1+a3 

<interactive>:1:3: 
    Couldn't match expected type `Feet' against inferred type `Meters' 
    In the second argument of `(+)', namely `a3' 
    In the expression: a1 + a3 
    In the definition of `it': it = a1 + a3 
*Main> 

Ahora puede crear una clase de tipo de conversión para convertir ay de cualquier tipo de medida

class LengthMeasure unit where 
    untype :: unit -> Float 
    toFeet :: unit -> Feet 
    toFeet = Feet . (* 3.2808) . untype . toMeters 
    toMeters :: unit -> Meters 
    toMeters = Meters . (* 0.3048) . untype . toFeet 

instance LengthMeasure Feet where 
    untype = unFeet 
    toFeet = id 

instance LengthMeasure Meters where 
    untype = unMeters 
    toMeters = id 

Ahora podemos convertir libremente entre tipos:

*Main> a1+toFeet a3 
Feet {unFeet = 10.842401} 

Por supuesto, los paquetes para hacer este tipo de cosas son available en Haskell.

Dado que ya está utilizando Java, ¿quizás Scala o Clojure ofrecerían capacidades similares?

Cuestiones relacionadas