Thứ nhất, một số soạn sẵn:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances, UndecidableSuperClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
module ConstrainApplications where
import GHC.Exts (Constraint)
import Data.Type.Equality
Bây giờ gõ các gia đình để mổ xẻ các ứng dụng tại các loại tùy ý.
type family GetFun a where
GetFun (f _) = f
type family GetArg a where
GetArg (_ a) = a
Hiện tại, chức năng cực kỳ chung chung, cần thiết hơn để trả lời câu hỏi. Nhưng điều này cho phép một ràng buộc liên quan đến cả hai thành phần của ứng dụng.
type G (cfa :: (j -> k) -> j -> Constraint) (fa :: k)
= (fa ~ (GetFun fa :: j -> k) (GetArg fa :: j)
, cfa (GetFun fa) (GetArg fa))
Tôi không thích các chức năng ràng buộc cung cấp mà không có lớp học phù hợp, vì vậy đây là phiên bản hạng nhất của G
.
class G cfa fa => GC cfa fa
instance G cfa fa => GC cfa fa
Có thể bày tỏ F
sử dụng G
và một lớp phụ trợ:
class (cf f, ca a) => Q cf ca f a
instance (cf f, ca a) => Q cf ca f a
type F cf ca fa = G (Q cf ca) fa
class F cf ca fa => FC cf ca fa
instance F cf ca fa => FC cf ca fa
Dưới đây là một số mẫu sử dụng của F
:
t1 :: FC ((~) Maybe) Eq a => a -> a -> Bool
t1 = (==)
-- In this case, we deconstruct the type *twice*:
-- we separate `a` into `e y`, and then separate
-- `e` into `Either x`.
t2 :: FC (FC ((~) Either) Show) Show a => a -> String
t2 x = case x of Left p -> show p
Right p -> show p
t3 :: FC Applicative Eq a => a -> a -> GetFun a Bool
t3 x y = (==) <$> x <*> y
Có vẻ tốt hơn nếu bạn sử dụng FC như một inflix nhà điều hành. – 2426021684
'((~) Hoặc) \' FC \ 'Eq \' FC \ 'Eq' – 2426021684
@ 2426021684, điểm tốt. – dfeuer