Haskell Arrows внутри кортежей - PullRequest
       27

Haskell Arrows внутри кортежей

7 голосов
/ 27 февраля 2012

Я хочу создать кортеж, который содержит стрелку и строку, которая описывает стрелку.Если я делаю это с функциями (вместо стрелок), следующее работает как ожидалось:

funTimes10 = (*10)
describe10 = "times 10"

tuple10 :: (Num b) => ((b -> b), String)
tuple10 = (,) funTimes10 describe10

Я могу получить доступ к функции с помощью fst, а с помощью snd я получаю строку описания функции,

Однако, если я поменяю функцию со стрелкой, как показано ниже:

aTuple10 :: (Arrow a, Num b) => (a b b, String)
aTuple10 = (,) (arr funTimes10) describe10
  • fst все еще работает и возвращает мою стрелку, но
  • Я не получаю никакой строки описания с snd.

Я получил только это сообщение об ошибке:

Ambiguous type variable `a0' in the constraint:
  (Arrow a0) arising from a use of `aTuple10'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `snd', namely `aTuple10'
In the expression: (snd aTuple10)
In an equation for `it': it = (snd aTuple10)

Почему я получаю эту ошибку и что мне делать, чтобы ее избежать?

Ответы [ 2 ]

9 голосов
/ 27 февраля 2012

Давайте посмотрим на тип snd:

snd :: (foo, x) -> x

(я переименовал переменные типа для ясности)

Что такое состояние типа для кортежа с типами foo и x, вернуть что-то типа x.Здесь важно знать, что система ценностей ака.среда выполнения в Haskell ленива, система типов Haskell строгая, это означает, что оба типа foo и x должны быть известны до вызова snd.

В первом случае, когда вы простоиметь Num b => (b -> b, String), вызов snd оставит b неоднозначным, потому что вы нигде не упоминаете его конкретный тип, и он не может быть выведен из возвращаемого типа, потому что foo ~ b, который отличается от x,Другими словами: поскольку (b, b) может быть кортежем любого числового типа, а средство проверки типов не может выяснить, какой из них, это неоднозначно.Хитрость заключается в том, что у нас будут введены правила по умолчанию для Haskell, которые утверждают, что если числовой тип является неоднозначным, по умолчанию он должен быть Integer.Если бы вы включили предупреждения с помощью -Wall, он бы сказал, что это происходит.Таким образом, наш тип становится (Integer -> Integer, String) и может вызываться snd.

Однако во втором случае нам все же удается вывести b с помощью правил по умолчанию, но по умолчанию Arrow нетза a, поэтому мы застряли!Вы должны явно указать, какую стрелку вы хотите, чтобы продолжить!Вы можете сделать это, сначала используя значение aTuple10 где-то еще:

let bla = aTuple10  -- We do this because `aTuple10` can have type variables, but `bla` cannot (by default)
fst bla (23 :: Int) -- This fixes the type of `bla`, so that `a ~ (->)` and `b ~ Int`
print $ snd bla     -- So the arrow isn't ambiguous here

... или вы можете просто указать нужный тип:

print $ snd (aTuple10 :: (Int -> Int, String))

PS Если вы хотите изменить тип неоднозначных чисел по умолчанию, ключевое слово default может вам помочь.

0 голосов
/ 27 февраля 2012

Я пытался скомпилировать это:

import Control.Arrow

funTimes10 = (*10)
describe10 = "times 10"

tuple10 :: (Num b) => ((b -> b), String)
tuple10 = (,) funTimes10 describe10

aTuple10 :: (Arrow a, Num b) => (a b b, String)
aTuple10 = (,) (arr funTimes10) describe10

Но я получаю это:

Could not deduce (b ~ Integer)
from the context (Arrow a, Num b)
  bound by the type signature for
             aTuple10 :: (Arrow a, Num b) => (a b b, String)
  at D:\dev\haskell\arr_tuple.hs:10:1-42
  `b' is a rigid type variable bound by
      the type signature for
        aTuple10 :: (Arrow a, Num b) => (a b b, String)
      at D:\dev\haskell\arr_tuple.hs:10:1
Expected type: b -> b
  Actual type: Integer -> Integer
In the first argument of `arr', namely `funTimes10'
In the first argument of `(,)', namely `(arr funTimes10)'

Итак, я думаю, вам нужно решить, какой экземпляр стрелки вы хотите использовать. То есть вам может потребоваться указать конкретный тип arr funTimes с аннотацией.

...