是否有将约束应用于类型应用程序的一般方法?

dfe*_*uer 7 haskell typeclass type-families polykinds

用户2426021684评论让我调查是否有可能提出一个类型函数,以证明对于某些和:FF c1 c2 fafa

  1. fa ~ f a
  2. c1 f
  3. c2 a

事实证明,最简单的形式很容易.但是,我发现很难弄清楚如何编写多角度版本.幸运的是,当我写这个问题时,我设法找到了一种方法.

dfe*_*uer 6

首先,一些样板:

{-# 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
Run Code Online (Sandbox Code Playgroud)

现在键入族以解释任意类型的应用程序.

type family GetFun a where
  GetFun (f _) = f
type family GetArg a where
  GetArg (_ a) = a
Run Code Online (Sandbox Code Playgroud)

现在是一个非常通用的类型函数,比回答问题所需的更通用.但这允许涉及应用程序的两个组件的约束.

type G (cfa :: (j -> k) -> j -> Constraint) (fa :: k)
  = ( fa ~ (GetFun fa :: j -> k) (GetArg fa :: j)
    , cfa (GetFun fa) (GetArg fa))
Run Code Online (Sandbox Code Playgroud)

我不喜欢在没有类匹配的情况下提供约束函数,所以这里是一流的版本G.

class G cfa fa => GC cfa fa
instance G cfa fa => GC cfa fa
Run Code Online (Sandbox Code Playgroud)

表达F使用G和辅助类是可能的:

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
Run Code Online (Sandbox Code Playgroud)

以下是一些示例用法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
Run Code Online (Sandbox Code Playgroud)