Существует ли эквивалент Haskell единиц измерения F #?

F # имеет единицы измерения, описанные в http://msdn.microsoft.com/en-us/library/dd233243.aspx следующим образом:

[<Measure>] type unit-name [ = measure ]

Это позволяет определять единицы измерения, такие как:

type [<Measure>] USD
type [<Measure>] EUR

И код, который будет записан как:

let dollars = 25.0<USD>
let euros   = 25.0<EUR>

// Results in an error as the units differ
if dollars > euros then printfn "Greater!"

Он также обрабатывает конверсии (я предполагаю, что означает, что "Мера" имеет определенные функции, которые позволяют умножать, делить и экспонировать Меры):

// Mass, grams.
[<Measure>] type g
// Mass, kilograms.
[<Measure>] type kg

let gramsPerKilogram: float<g kg^-1> = 1000.0<g/kg>

let convertGramsToKilograms (x: float<g>) = x / gramsPerKilogram

Мои инстинкты говорят мне, что в Haskell возможно реализовать аналогичную возможность, но я не смог найти примеров того, как это сделать.

Изменить: о, мое слово, это огромная баня червей! Там есть исследовательский документ http://research.microsoft.com/en-us/um/people/akenn/units/CEFP09TypesForUnitsOfMeasure.pdf. Я предполагаю, что это более чем несколько строк кода для реализации всего. Летний проект?:)

Ответы

Ответ 1

Заверните числа в newtype и дайте им экземпляр Num.

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype GBP n = GBP n deriving (Show, Num, Eq, Ord)
newtype USD n = USD n deriving (Show, Num, Eq, Ord)

Использование:

ghci> let a1 = GBP 2
ghci> let a2 = GBP 5
ghci> a1 + a2
GBP 7
ghci> let b1 = USD 3
ghci> let b2 = USD 6
ghci> b1 + b2
USD 9
ghci> a1 + b2 -- should be an error for mixing currencies

<interactive>:8:6:
    Couldn't match expected type `GBP Integer'
                with actual type `USD Integer'
    In the second argument of `(+)', namely `b2'
    In the expression: a1 + b2
    In an equation for `it': it = a1 + b2

Ответ 2

dimensional и dimensional-tf ( с типами семейств вместо классов с несколькими параметрами) библиотеки довольно приятны и могут обрабатывать большинство проблем, представленных в вашем примере.

Я не думаю, что библиотека позволяет вам определять настраиваемые параметры, такие как валюты. Насколько я знаю, вам нужно будет изменить код библиотеки, чтобы сделать это.

Ответ 3

OK. Я знаю, что вопрос слишком стар. Но есть сборка плагина GHC для обеспечения возможности единицы измерения в Haskell. Пожалуйста, обратитесь к этому документу Adam Gundry .

Ответ 4

Пакет units кажется многообещающим и позволяет конвертировать между различными единицами того же размера. Тем не менее, я не использовал его, и я не знаю, стабилен он или нет. Справедливости ради, я попытался установить его сегодня, и установка завершилась неудачно...

Ответ 5

Проверьте haskell.org wikipage о том, как принудительно использовать блоки в Haskell:

https://wiki.haskell.org/Physical_units

Существует несколько вариантов, но я не уверен, действительно ли что-то похожее на "Единицы измерения", которые вы упомянули.

Ответ 6

Я не знаю Haskell, хотя я заинтересован в обучении и все еще младше с F #, однако, кажется, общее решение должно быть связано с обработкой мер как кортежа скаляра и метки, представляющей единицу, (N, М).

Например, пусть мера является общим набором из measure<N,M>, где N является числом, а M является string, тогда =, +, -, *, /, ^ может быть перегружен для реализации оценки для данных мер, a, b, and c, скаляр p, boolean k и нормировочная функция метки метки norm такая, что

a = b = (Na,Ma) = (Nb,Mb) = (Na = Nb) and norm(Ma) = norm(Mb) = k
a + b = (Na,Ma) + (Nb,Mb) = (Na + Nb, Ma) = c provided norm(Ma) = norm(Mb)
a * b = (Na,Ma) * (Nb,Mb) = (Na * Nb, Ma * Mb) = c
a ^ p = (Na,Ma) ^ p       = (Na ^ p , Ma ^ p ) = c
....