2013-01-04 38 views
5

Tôi đang làm việc trên một hàm functor có chứa một monoid để "xem" việc thực hiện. Tuy nhiên, đôi khi tôi không quan tâm đến phần này chút nào, vì vậy sự lựa chọn của monoid là không liên quan vì nó sẽ không bao giờ được tiêu thụ. Tôi đã đơn giản hóa những gì tôi có vào:Sử dụng các loại ràng buộc và loại gia đình có hạn chế 'giới hạn'

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE ConstraintKinds #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE TypeFamilies #-} 

import GHC.Exts 

class Render a b where render :: a -> b 
instance Render a() where render = const() 

class Merge a where 
    type Renderer a b :: Constraint 
    merge :: Renderer a b => a -> b 

data Foo = Foo Bool 

instance Merge Foo where 
    type (Renderer Foo) m = (Render Bool m) 
    merge (Foo b) = render b 

Render được sử dụng để chuyển đổi khác nhau a s thành một đơn b. Merge là một đơn giản hóa lớn của functor thực tế của tôi, nhưng điểm là nó chứa một loại gia đình/hạn chế và ý định của tôi là xác định chính xác những gì Render ers a Merge yêu cầu.

Bây giờ, tôi có thể muốn "chạy" các Merge, nhưng loại bỏ các quan điểm, mà là giống như một cái gì đó như:

runFoo :: Merge a => a -> Int 
runFoo x = case merge x of() -> 5 

Nhưng điều này sẽ thất bại vì:

Không thể suy ra (Renderer a()) phát sinh từ việc sử dụng của merge

tôi đã chọn () như monoid của tôi bởi vì f orall a, chúng tôi có một phiên bản Render a(). Vì vậy, nếu có một cách để nói rằng Merge a chỉ có nghĩa là một bộ sưu tập Render ràng buộc sau đó điều này sẽ làm việc tốt. Tất nhiên, Merge a là tổng quát hơn thế - nó có thể thêm các ràng buộc tùy ý, giải thích lỗi biên dịch.

Có cách nào để đạt được những gì tôi muốn mà không cần thay đổi chữ ký của runFoo?

+0

Liệu 'Renderer' luôn bao gồm chính xác một' Render'? –

+0

@Tinctorius - không, nói chung phụ thuộc vào số lượng các loại riêng biệt trong các trường 'Foo' – ocharles

+0

Có lý do tại sao' Merge' không có 'b' làm tham số không? –

Trả lời

6

này có thể không mở rộng nếu bạn có rất nhiều những trường hợp này, nhưng hoạt động này:

class Renderer a() => Merge a where 
    ... 
+0

Tôi đã không xem xét điều đó. Tôi có thể đọc được ràng buộc đó là ''Merge' nên ít nhất hỗ trợ hiển thị bằng '()' monoid'. Tuy nhiên, điều này không phải là 'UndecidableInstances'. – ocharles

+0

"UndecidableInstances không phải là một lá cờ nguy hiểm. Nó sẽ không bao giờ làm cho trình kiểm tra kiểu chấp nhận một chương trình" sai ". Hậu quả xấu nhất của việc sử dụng cờ là trình kiểm tra kiểu có thể cho chúng ta biết rằng nó không thể quyết định xem chương trình của chúng ta có được đánh máy tốt hay không, với giới hạn chiều sâu theo ngữ cảnh. " http://okmij.org/ftp/Haskell/TypeClass.html#undecidable-inst-defense –

+0

Tôi biết rằng, tôi đã sử dụng nó ở 3 nơi khác;) Nhưng lý tưởng là tôi muốn tìm các giải pháp không yêu cầu nó, ngay cả khi vì lý do học tập hoàn toàn. Tôi có lẽ sẽ chấp nhận câu trả lời này, chỉ cần rời khỏi mặt đất mở cho một chút lâu hơn mặc dù. Điều này thực sự làm việc một điều trị! – ocharles

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