2012-02-27 11 views
7

Chcę utworzyć skrzynię zawierającą strzałkę i ciąg znaków opisujący strzałkę. Jeśli mogę to zrobić z funkcji (zamiast strzałek), następujące prace jak spodziewanych:Haskell Strzały wewnątrz krotek

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

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

mogę uzyskać dostęp do funkcji z fst iz snd otrzymuję ciąg opis funkcji.

Jednakże, jeśli mogę wymienić funkcję ze strzałką, jak w poniższym przykładzie:

aTuple10 :: (Arrow a, Num b) => (a b b, String) 
aTuple10 = (,) (arr funTimes10) describe10 
  • fst nadal działa i zwraca moją strzałkę, ale
  • ja nie dostać dowolny ciąg opis ze snd.

Mam tylko tego błędu wiadomość:

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) 

Dlaczego mam ten błąd, i co należy zrobić, aby tego uniknąć? wygląd

Odpowiedz

9

Miejmy w rodzaju snd:

snd :: (foo, x) -> x 

(I przemianowany zmienne typu dla jasności)

Co stany typu jest to, że za krotki z typów foo i x, coś z powrotu typ x. Ważne jest, aby wiedzieć, że podczas gdy system wartości aka. runtime w Haskell jest leniwy, system typu Haskella jest ścisły, co oznacza, że ​​oba typy foo i x muszą być znane przed wywołaniem snd.

W pierwszym przypadku, gdy po prostu masz Num b => (b -> b, String), nazywając snd pozostawi b dwuznaczny, ponieważ nie wspominając swój konkretny typ wszędzie, i nie można wywnioskować z zwracanego typu bo foo ~ b która jest odrębna od x. Innymi słowy: ponieważ (b, b) może być krotką dowolnego typu numeru, a narzędzie sprawdzania typu nie może ustalić, który z nich jest niejednoznaczny. Podejście polega na tym, że mamy reguły Haskella, które są domyślne, co oznacza, że ​​jeśli typ liczbowy jest niejednoznaczny, powinien on być domyślnie ustawiony na Integer. Jeśli włączono ostrzeżenia z numerem -Wall, powiedziałoby się, że tak się dzieje. Tak więc nasz typ staje się (Integer -> Integer, String) i snd może być wywołany.

W drugim przypadku jednak nadal możemy wywnioskować b za pomocą reguł domyślnych, ale nie ma domyślnego Arrow dla a, więc utknęliśmy! Musisz jasno określić strzałkę, którą chcesz, aby kontynuować! Można to zrobić albo przez pierwszy stosując wartość aTuple10 gdzieś indziej:

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 

...lub można po prostu określić typ, który chcesz:

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

PS jeśli chcesz zmienić domyślny typ liczb niejednoznacznych The default keyword może pomóc.

+0

to dokładnie to;) thx – frosch03

+1

Jak irytujące. Można by się spodziewać, że system typów będzie w stanie wywnioskować, że 'snd aTuple10' ma typ' String'; czy można to uznać za błąd w implementacji? Z pewnością Haskell 2010 nie określa takiego zachowania. Można by argumentować, że jeśli implementacja nie wie, jaki typ ma pierwsza rzecz, nie będzie wiedzieć, gdzie w pamięci jest druga rzecz, ale skoro mamy tutaj do czynienia z pudełkowymi krotkami, zawsze powinny być dwa wskaźniki, a zatem drugi element można łatwo zlokalizować niezależnie od typu pierwszego. –

+2

Funkcja taka jak "klasa Boolish a gdzie toBool :: a -> Bool; foo :: Boolish a => (a, b) -> b; foo (a, b) = jeśli doBool a następnie b else undefined' jest możliwe, więc wynik funkcji może zależeć od niejednoznacznego parametru. Specjalna obudowa 'snd' byłaby dziwna w tej sytuacji. – dflemstr

-1

Próbowałem skompilować to:

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 

Ale mam to:

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)' 

Tak, wydaje mi się, że trzeba zdecydować, które strzałka instancja chcesz użyć. To znaczy. może być konieczne określenie konkretnego typu arr funTimes z adnotacją.

+0

Błąd tutaj jest całkowicie niezwiązany z problemem w zasięgu ręki. Pojawia się, ponieważ zapomniałeś podpisu typu dla 'funTimes10'. Sprawdź [Ograniczenie Monomorfizmu] (http://www.haskell.org/haskellwiki/Monomorphism_restriction). – dflemstr

+0

@dflemstr czy moja odpowiedź pokazuje problem z pierwotnym pytaniem? ** Ja ** nie zapomniałem podpisu typu, którego nie było w oryginalnym poście. Chociaż nie opisałem problemu leżącego u jego podstaw (ponieważ go nie widziałem), nie sądzę, że warto obalić moją odpowiedź. – Andre

+1

Sądzę, że PO po prostu skopiował definicję jego funkcji, aby pokazać, jakiego rodzaju wartości używa. Ma polimorficzny "funTimes10", inaczej uzyskałby inny błąd. – dflemstr