Как вычитание типа работает в Haskell? - PullRequest
10 голосов
/ 29 августа 2009

Я пытаюсь расширить свой кругозор, изучая Haskell.

Моя домашняя работа была связана с созданием тактового генератора, который давал бы мне интервалы, распределенные по Пуассону, и конечный результат (после долгой борьбы, я признаю) был следующим:

import System.Random
poissonStream :: ( Ord r, Random r, Floating r, RandomGen g) => r -> r -> r -> g -> [r]
poissonStream rate start limit gen 
        | next > limit = [] 
        | otherwise     = next:(poissonStream rate next limit newGen)
        where  (rvalue, newGen) = random gen
               next = start - log(rvalue) / rate  

Но есть две вещи (по крайней мере), которые я не понимаю:

Зачем мне нужно "Ord r" и "Floating r"? (Я бы ожидал какое-то автоматическое наследование: «Плавающий» подразумевает «Орд».)

По какому пути достигается подразумеваемое определение типа "rvalue :: Float"? В GHCi я получаю то, что ожидал:

*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100)
<interactive>:1:23:
    Ambiguous type variable `t' in the constraint:
      `Random t' arising from a use of `random' at <interactive>:1:23-43
    Probable fix: add a type signature that fixes these type variable(s)

rvalue - свободная пушка, которую я должен связать:

*Main System.Random> let (rvalue, newGen) = random (mkStdGen 100) :: (Float, StdGen)
*Main System.Random> rvalue
0.18520793

Пожалуйста, будьте осторожны с Haskell n00b.

Ответы [ 2 ]

12 голосов
/ 29 августа 2009

Зачем мне нужен "Ord r" и "Floating r"? (Я бы ожидал какое-то автоматическое наследование: «Плавающий» подразумевает «Орд».)

Floating должен классифицировать все числа с плавающей запятой, включая сложные. Там нет порядка для комплексных чисел. Вы можете использовать RealFloat вместо Floating, что подразумевает Ord.

По какому пути достигается подразумеваемое определение типа "rvalue :: Float"?

Ну, вы можете вывести это из контекста, в котором используется rvalue. Это аргумент для log и

:t log

дает

log :: (Floating a) => a -> a

, поэтому rvalue должно быть в классе Floating (поэтому это будет "некоторый тип в классе типов Floating, а не точно Float). Кроме того, результат log имеет тот же тип в качестве входных данных и используется в вычислениях с start и rate и сравнивается с limit, которые имеют тип r, поэтому rvalue будет иметь r (что подходит, потому что r также имеет Floating.

В вашем примере GHCi больше нет контекста. Тип

 :t random (mkStdGen 100)

Это дает вам

random (mkStdGen 100) :: (Random a) => (a, StdGen)

GHCi не знает, какой тип для заполнения a здесь. Он только знает, что должен быть в классе типов Random.

2 голосов
/ 29 августа 2009

В Haskell, Ord и Floating являются независимыми или ортогональными понятиями. Возможно, вы предполагали, что Floating относится только к очень конкретным типам, таким как Double и Float (это будет иметь место в большинстве других языков)?

Как указал Рудигер, есть типы, которые являются экземплярами класса Floating, которые не являются Ord, потому что нет порядка для определенных типов с плавающей точкой, таких как Complex. Другим примером, кроме комплексных чисел, были бы векторы, для которых вы можете определять эти плавающие функции, но не какой-либо разумный порядок.

Помните, что классы типов просто задают набор функций (например, интерфейс в Java или C #, если это полезно для понимания), которые должны быть определены для типа a ; чтобы быть Ord, тип a просто нуждается в операторах сравнения, а чтобы быть экземпляром Floating, тип a просто должен реализовать Fractional и иметь функции pi, exp, sqrt, log, sin, cos, ... определено для них. Это все плавающие средства, ни больше, ни меньше.

...