2012-02-27 34 views
7

Tôi muốn vẽ một bộ túp, giữ một mũi tên và một chuỗi mô tả mũi tên. Nếu tôi làm như vậy với chức năng (thay vì mũi tên), các công trình sau đây như mong đợi:Mũi tên Haskell bên trong Tuples

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

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

tôi có thể truy cập vào các chức năng với fst, và với snd tôi nhận được chuỗi mô tả của hàm.

Tuy nhiên, nếu tôi trao đổi các chức năng với một mũi tên, giống như trong những điều sau đây:

aTuple10 :: (Arrow a, Num b) => (a b b, String) 
aTuple10 = (,) (arr funTimes10) describe10 
  • fst vẫn hoạt động và trả về mũi tên của tôi, nhưng
  • tôi không nhận được bất kỳ chuỗi mô tả với snd.

Tôi chỉ có này lỗi thông điệp:

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) 

Tại sao tôi nhận được lỗi này, và những gì tôi nên làm gì, để tránh nó?

Trả lời

9

Hãy nhìn vào các loại snd:

snd :: (foo, x) -> x 

(tôi đổi tên các biến kiểu cho rõ ràng)

gì các quốc gia loại là đối với một tuple với các loại foox, trở về một cái gì đó nhập x. Một cái gì đó quan trọng cần biết ở đây là trong khi hệ thống giá trị aka. thời gian chạy trong Haskell là lười biếng, hệ thống kiểu Haskell là nghiêm ngặt, có nghĩa là cả hai loại foox phải được biết trước khi snd có thể được gọi.

Trong trường hợp đầu tiên, khi bạn chỉ có một Num b => (b -> b, String), gọi snd sẽ rời b mơ hồ, bởi vì bạn không đề cập đến kiểu dữ liệu cụ của nó bất cứ nơi nào, và nó không thể được suy ra từ các kiểu trả về vì foo ~ b đó là khác biệt từ x. Nói cách khác: vì (b, b) có thể là một bộ gồm bất kỳ loại số nào và trình kiểm tra loại không thể tìm ra loại nào, nó không rõ ràng. Bí quyết ở đây là chúng ta sẽ có các quy tắc mặc định của Haskell khởi động, cho biết nếu một kiểu số không rõ ràng, nó sẽ mặc định là Integer. Nếu bạn đã bật cảnh báo với -Wall, điều đó sẽ xảy ra. Vì vậy, loại của chúng tôi trở thành (Integer -> Integer, String)snd có thể được gọi.

Trong trường hợp thứ hai, tuy nhiên, chúng tôi vẫn quản lý suy ra b thông qua quy tắc mặc định, nhưng không có mặc định Arrow cho a, vì vậy chúng tôi bị kẹt! Bạn phải chỉ định rõ ràng mũi tên nào bạn muốn để tiếp tục! Bạn có thể thực hiện việc này trước tiên bằng cách sử dụng giá trị aTuple10 ở một nơi khác:

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 

...hoặc bạn chỉ có thể xác định loại mà bạn muốn:

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

PS nếu bạn muốn thay đổi kiểu mặc định của số mơ hồ, các default keyword có thể giúp bạn ra ngoài.

+0

chính xác là vậy;) thx – frosch03

+1

Kích thích như thế nào. Người ta sẽ mong đợi hệ thống kiểu có thể kết luận rằng 'snd aTuple10' có kiểu' String'; điều này có thể được coi là một lỗi trong việc thực hiện? Chắc chắn Haskell 2010 không xác định hành vi như vậy. Người ta có thể tranh luận rằng nếu việc thực hiện không biết loại đầu tiên có, nó sẽ không biết vị trí trong bộ nhớ thứ hai là gì, nhưng vì chúng ta đang xử lý các bộ đóng hộp ở đây, nên luôn có hai con trỏ, và do đó yếu tố thứ hai có thể dễ dàng định vị bất kể loại đầu tiên. –

+2

Một chức năng như 'lớp Boolish một nơi toBool :: a -> Bool; foo :: Boolish a => (a, b) -> b; foo (a, b) = nếu toBool a thì b else undefined' là conceivable, do đó kết quả của hàm có thể phụ thuộc vào tham số mơ hồ. Đặc biệt vỏ bọc cho 'snd' sẽ là lạ trong tình huống đó. – dflemstr

-1

tôi đã cố gắng để biên dịch này:

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 

Nhưng tôi có được điều này:

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

Vì vậy, tôi đoán là bạn cần phải quyết định mà mũi tên Ví dụ bạn muốn sử dụng. I E. bạn có thể cần xác định loại cụ thể là arr funTimes bằng chú thích.

+0

Lỗi ở đây hoàn toàn không liên quan đến vấn đề ở bàn tay. Nó xuất hiện vì bạn đã quên chữ ký loại cho 'funTimes10'. Kiểm tra [Hạn chế monomorphism] (http://www.haskell.org/haskellwiki/Monomorphism_restriction). – dflemstr

+0

@dflemstr câu trả lời của tôi có hiển thị vấn đề với câu hỏi gốc không? ** I ** không quên chữ ký loại, nó không có trong bài gốc. Mặc dù tôi không mô tả vấn đề cơ bản (bởi vì tôi không nhìn thấy nó), tôi không nghĩ rằng nó có giá trị downvoting câu trả lời của tôi. – Andre

+1

Tôi nghĩ rằng OP chỉ sao chép định nghĩa của các chức năng của mình để chứng minh các loại giá trị anh ta đang sử dụng. Anh ta có một 'funTimes10' đa hình, hoặc anh ta sẽ nhận được một lỗi khác. – dflemstr

Các vấn đề liên quan