2015-12-21 17 views
7

tâm chương trình Reflex này:Hai chức năng biên dịch với chú thích kiểu. Xóa một chú thích - không biên dịch. Loại bỏ hai - biên dịch một lần nữa. Tại sao?

{-# LANGUAGE ScopedTypeVariables, RecursiveDo #-} 

import Control.Applicative 
import Control.Monad 
import Control.Monad.IO.Class 
import Prelude hiding (div) 
import Reflex.Dom 
import qualified Data.Map as M 

clickMe :: MonadWidget t m => m (Event t()) 
clickMe = do 
    rec (e,_) <- elAttr' "button" M.empty (display c) 
     c :: Dynamic t Int <- count (domEvent Click e) 
    return $ domEvent Click e 

div :: forall t m a . MonadWidget t m => m a -> m a 
div = elAttr "div" ("style" =: "border : 1px solid black") 

app :: forall t m . MonadWidget t m => m() 
app = div $ do 
    aClicks <- clickMe 
    bClicks <- clickMe 
    a <- count aClicks 
    b <- count bClicks 
    l <- combineDyn (\a b -> replicate (a-b)()) a b 
    simpleList l (const clickMe) 
    return() 

main = mainWidget app 

Nếu bạn loại bỏ các loại chú thích từ một trong hai div hoặc app, chương trình sẽ không biên dịch với một lỗi loại khổng lồ đáng sợ. Nếu bạn xóa cả hai, nó sẽ biên dịch lại. Từ quan điểm của một lập trình viên, điều này mang lại trải nghiệm người dùng khủng khiếp khi ai đó đang cố gắng chú thích từng bước một chương trình không được báo cáo. Nó không có ý nghĩa rằng việc thêm một chú thích kiểu đúng vào một thuật ngữ không được viện dẫn sẽ gây ra lỗi trình biên dịch, và nó dẫn người lập trình nghĩ rằng anh ta có kiểu sai.

This is the error you get by removing div's annotation.

Those are the inferred types.

Tại sao điều này xảy ra?

+0

Loại suy ra khi bạn loại bỏ các loại là gì? Làm thế nào để họ so sánh với các loại được cung cấp? Đây là một suy đoán nhưng tôi nghĩ rằng một trong những loại suy ra hoặc cung cấp không phải là chung chung đủ và do đó kết xuất không tương thích. Ngoài ra, việc thêm các loại suy luận có thể giúp trả lời câu hỏi. – concept3d

+2

Tôi đã bao gồm các loại suy luận về câu hỏi ngay bây giờ, mặc dù tôi không thể hiểu chúng như có nhện. – MaiaVictor

+2

hạn chế monomorphism –

Trả lời

4

Điều này là do hạn chế monomorphism. Khi trình biên dịch đánh máy một liên kết cấp cao nhất mà không có chú thích kiểu, nó sẽ không gán một loại đa hình nếu kiểu đó có ràng buộc và hàm không có đối số cú pháp, là trường hợp cho cả hai chức năng của bạn là.

Tuy nhiên, nếu bạn bao gồm không phải là chữ ký loại, nó vẫn không biên dịch. Trong trường hợp của bạn, bạn đã cung cấp thêm một số thông tin (phần foo = [app, _]) và vì lý do nào đó, chọn loại hình đơn nhất - Tôi không biết điều gì đã thay đổi về môi trường của bạn nhưng đó không phải là hành vi tiêu chuẩn.

Đây là một tập tin đơn giản chưng cất các vấn đề bạn đang gặp:

{-# LANGUAGE RankNTypes, KindSignatures, MultiParamTypeClasses, FunctionalDependencies #-} 

module Test where 

import Prelude hiding (div) 

class MonadWidget t (m :: * -> *) | m -> t 

div :: forall t m a . MonadWidget t m => m a -> m a 
div = (undefined :: forall t m a . MonadWidget t m => m a -> m a) 

app :: forall t m . MonadWidget t m => m() 
app = (div (undefined :: forall t m . MonadWidget t m => m()) 
     :: forall t m . MonadWidget t m => m()) 

Nếu bạn nhận xét ra một trong hai loại chữ ký, hoặc cả hai, bạn sẽ được đáp ứng với một lỗi. Tuy nhiên, hãy chú thích bất kỳ chữ ký loại cấp cao nhất nào, nhưng chạy bằng ghc -XNoMonomorphismRestriction Test.hs và nó sẽ biên dịch thành công trong mọi cấu hình. Hereareafewtests.

+0

Cảm ơn. Tại thời điểm này, tôi nghĩ rằng nếu tôi chỉ nên vô hiệu hóa các hạn chế monomorphism theo mặc định. – MaiaVictor

1

Như Reid Barton đã lưu ý trong nhận xét, điều này là do The Dreaded Monomorphism Restriction.

đây được đơn giản hóa ví dụ:

foo :: Monad m => m a -> m a 
foo = (>>= return) 

bar :: Monad m => m() 
bar = foo (return()) 

Khi hạn chế monomorphism kích hoạt và loại chữ ký foo 's nhận xét:

  • GHC cố gắng gán loại monomorphic để đến foo và thất bại vì không có mặc định Monad bản sao:

Không dụ cho (Monad M0) phát sinh từ việc sử dụng của '>> ='
Loại biến 'M0' là mơ hồ

  • sử dụng foo tại bar dẫn đến một lỗi mà tôi không thể giải thích

không thể phù hợp với loại 'M0' với 'm'
vì loại biến 'm' sẽ thoát khỏi phạm vi của nó

Thêm {-# LANGUAGE NoMonomorphismRestriction #-} pragma sửa lỗi này và cho phép thêm chữ ký kiểu tăng dần.

+0

'Thêm {- # LANGUAGE NoMonomorphismRestriction # -} pragma sửa lỗi này và cho phép thêm chữ ký kiểu gia tăng.' - Điều này có đúng không? – MaiaVictor

+0

Có, nếu lỗi là do hạn chế monomorphism. Mặt khác, vô hiệu hóa MR theo mặc định có thể dẫn đến giảm chia sẻ, nhưng tình huống khá hiếm này. –

+0

[Ở đây] (http://lambda.jstolarek.com/2012/05/towards-understanding-haskells-monomorphism-restriction/) là giải thích về cách MR ảnh hưởng đến việc chia sẻ. –

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