2013-11-02 7 views
1

Я недавно начал играть с единицами измерения в F # и думал, что могу написать очень простой пример, который вычисляет валовую сумму с учетом НДС и общий итог.Использование единиц измерения F # для вычисления валовой суммы с чистой суммы + сумма НДС

Например:

Чистая сумма может быть равна 600.00 ставка НДС будет 20% Какой должна дать Gross сумму 720.00

У меня есть следующие типы

[<Measure>] type net 
[<Measure>] type vatRate 
[<Measure>] type vatValue = net * vatRate 
[<Measure>] type gross 

И следующие функции

let calculateVat (netValue : float<net>) (vat : float<vatRate>) = netValue * vat 
let calculateGross (netValue : float<net>) (vat : float<vatValue>) = netValue + vat 

С помощью следующих тестов:

let calcVatTest = calculateVat 600.00<net> 0.2<vatRate> = 120.00<vatValue> 
let calcGrossTest = calculateGross 600.00<net> 120.00<vatValue> = 720.00<gross> 

Проблема у меня в том, что я не могу получить правильный синтаксис для функции calculateGross, и я получаю ошибку компиляции: «Единица измерения" vatValue»не соответствует единица измерения" чистой»

кажется, что мне нужно определить валовые похожее на следующее:

[<Measure>] type gross = net + vatValue 

Но компилятор не нравится +

Любые идеи, как я могу это достичь?

Благодаря

ответ

0

В вашей выборке, проблема заключается в том, что вы пытаетесь добавить две вещи с разными единицами (цена без НДС и стоимости НДС) - это не разрешенный статическим типом - вы можете добавлять только вещи одного и того же подразделения (что является частью принципов, лежащих в основе единиц измерения - вы не можете с этим поделать).

Я думаю, что наиболее естественное решение (что, впрочем, не дает вам надежных гарантий безопасности), было бы сделать безразмерное количество НДС.

В целом (если думать о физическом смысле), ставки являются примерами числа, которые не имеют единиц - скорость, как правило, рассчитываются как X<unit>/Y<unit> для некоторых чисел X и Y тех же unit и поэтому блок сокращается во время дивизион.

Таким образом, вы могли бы написать что-то вроде этого:

[<Measure>] type net 
[<Measure>] type vatRate = 1 
[<Measure>] type vatValue = net * vatRate 

let calculateVat (netValue : float<net>) (vat : float<vatRate>) = netValue * vat 
let calculateGross (netValue : float<net>) (vat : float<vatValue>) = netValue + vat 

Это означает, что float<vatRate> действительно будет просто обычным float и vatValue таким же, как net (но вы все еще можете использовать псевдонимы в коде в качестве документации).

Таким образом, это устраняет разницу между ценой с НДС и ценой без НДС, но по крайней мере ваша программа все еще статически различает поплавок, представляющий деньги, и float, представляющие только цифры.

+0

VatRate = 1 работает красиво. Есть ли способ, чтобы метод calculateGross возвращал тип float ? –

+0

Если вы используете 'vatRate = 1', тогда система единиц измерения не может различать значения, которые имеют тип' float ' и 'float ' - потому что они означают одно и то же. Вы должны иметь возможность добавлять аннотацию ': float ', но на самом деле - она ​​отслеживает разницу между _number_ или _rate_ и числом, означающим _money_. –

1

Только операторы *, / и ^ поддерживаются в меру выражения — хотя - могут быть использованы для создания отрицательного показателя степени. Логично, что это имеет смысл, потому что для использования анализа размеров компилятор должен учитывать каждый фактор, состоящий из скаляра и отдельных единиц или продукта единиц.

Честно говоря, это не очень удобно использовать для единиц измерения. Похоже, это просто усложняет ваш код, не придавая слишком большой выразительности.

Дальнейшее чтение

1

Я знаю, что вы не спрашивали, но это слишком большой вопрос, чтобы пройти, и это слишком много, чтобы вставить комментарий. Я думаю, что, вероятно, вы не хотите единицы измерения для брутто, vatRate и т. Д., Потому что я ожидаю, что брутто, нетто и т. Д. Будут в валюте.

Что-то больше, как это (предполагается, что НДС является процент европейской валюты):

[<Measure>] type euro 

[<Measure>] type percent 

let gross = 100.0<euro> 
let vatRate = 5.0<percent> 

Я хочу сказать, что я думаю, что вы получили в руки неправильно использовать единицы измерения. Гросс не единица измерения - это число; также vatRate.

+2

Это имеет смысл. Я думаю, что я пытался использовать Единицы измерения как способ сделать все, что это свой собственный тип, чтобы вы не могли случайно использовать чистую стоимость в виде валового значения, которое, как вы и pswg, указывает на то, что злоупотребление. С тех пор я переключился на то, чтобы эти типы были дискриминированным соединением, а именно Тип Всего = | Net of float | Валовой остаток поплавка Что определенно работает лучше. Спасибо за ответ, кстати. У меня есть много, чтобы узнать, что такие комментарии очень полезны –