Haskell 查找并匹配参数化参数

Haskell 查找并匹配参数化参数,haskell,type-families,Haskell,Type Families,是否可以通过类型族或其他方式为任意类型匹配类型参数 我试图写一个类型函数 type family Match s t a 它采用两种结构,s和t(假设两种不同的参数化类型相同,例如可能是Int和可能是String)和一个将与之匹配的参数。如果找到匹配的参数,则type函数提供替换。否则,它将提供原始参数 Match (Maybe a) (Maybe b) a ~ b Match (Maybe a) (Maybe b) c ~ c 我尝试的实现: {-# LANGUAGE TypeFamil

是否可以通过类型族或其他方式为任意类型匹配类型参数

我试图写一个类型函数

type family Match s t a
它采用两种结构,
s
t
(假设两种不同的参数化类型相同,例如
可能是Int
可能是String
)和一个将与之匹配的参数。如果找到匹配的参数,则type函数提供替换。否则,它将提供原始参数

Match (Maybe a) (Maybe b) a ~ b
Match (Maybe a) (Maybe b) c ~ c 
我尝试的实现:

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE PolyKinds #-}

import Data.Type.Equality
import Data.Type.Bool

type family Match (s::k) (t::k) (a :: * ) :: * where
  Match (f a :: *) (g b :: *) c = If ((a == c)) b c
找到参数后,族显然按计划工作:

>  :t (undefined :: (Match (Maybe a) (Maybe b) a))
(undefined :: (Match (Maybe a) (Maybe b) a)) :: b
但不适用于不匹配的情况:

 >  :t (undefined :: (Match (Maybe a) (Maybe b) c))
     Couldn't match type ‘If
                             ghc-prim-0.5.0.0:GHC.Types.*
                             (Data.Type.Equality.EqStar a0 c0)
                             b0
                             c0’
                     with ‘If
                             ghc-prim-0.5.0.0:GHC.Types.*   (Data.Type.Equality.EqStar a c) b c’
      Expected type: Match * (Maybe a) (Maybe b) c
        Actual type: Match * (Maybe a0) (Maybe b0) c0
      NB: ‘If’ is a type function, and may not be injective
      The type variables ‘a0’, ‘b0’, ‘c0’ are ambiguous
    • In the ambiguity check for an expression type signature
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      In an expression type signature: Match (Maybe a) (Maybe b) c
      In the expression: (undefined :: Match (Maybe a) (Maybe b) c)
像我所问的可能吗?它不必是类型家族,我对其他方法持开放态度。OTOH,允许模棱两可的类型在这里有用吗?我不知道陷阱,所以我犹豫了


谢谢

你要求的是两件不同的事情。你找的

[类型函数]采用两种结构,
s
t
(假设相同类型的两种不同参数化,例如
可能是Int
可能是String
)和一个将与之匹配的参数。如果找到匹配的参数,则type函数提供替换。否则,它将提供原始参数

你基本上已经写好了。您可能应该避免使用
(==)
,因为您可以使用非线性匹配,这通常优于:

type family Match (a :: i) (b :: i) (c :: o) :: o where
    Match (f a) (f b) a = b
    Match (f a) (f b) b = a
    Match _     _     c = c
稍后,您将定义两个函数,并希望两者都进行编译

undefined :: Match (Maybe a) (Maybe b) a
undefined :: Match (Maybe a) (Maybe b) c
第一个参数采用两种类型:

\@(a :: Type) @(b :: Type) -> (undefined :: Match (Maybe a) (Maybe b) a)
类型签名匹配第一个等式
Match
,并减少为
a

\@(a :: Type) @(b :: Type) -> (undefined :: a)
允许为未定义的函数推断正确的参数:

\@a @(b :: Type) -> undefined @'GHC.Types.LiftedRep @a
第二个功能是

\@(a :: Type) @(b :: Type) @(c :: Type) -> (undefined :: Match (Maybe a) (Maybe b) c)
将参数推断为
未定义
是不正确的,因为类型族应用程序
匹配(可能是a)(可能是b)c
。关于“不明确类型”错误有很多问题,其中包含原因。相反,必须减少类型族应用程序。但它不能减少。它匹配第三个等式,但如果
a~c
b~c
,它也可能匹配第一个和第二个等式,因此在主等式仍然可用时跳转到备用选项是不正确的。你可能会问,“为什么
a
/
b
c
没有区别?”答案是
a
b
c
只是变量(碰巧是类型变量)和值的名称(碰巧是类型)。这些值作为函数的参数提供。如果我给你
x,y::Int
,问你
的值,如果x==y,那么“是”或者“否”
,你就不能告诉我,因为你不知道
x
y
的值。然而,你问过哈斯克尔,“这里,
a,b,c::Type
。如果a==c,那么b else是什么?如果b==c,那么a else是c?”,这同样是无法回答的。没有办法区分具有相同值的变量,因为这会破坏Haskell的基础

注意,我给你的问题有一个相当厚颜无耻的答案。您可以说“如果x==y,则
的值为“是”,否则“否”
如果x==y,则“是”,否则“否”
“类似地,我可以进入并手动向
未定义的
提供未简化类型族应用程序的类型参数,通过允许不明确的类型来定义您的函数。不再需要通过尝试(但失败)减少
匹配
应用程序来推断
未定义
的参数是什么

fun :: forall a b c. Match (Maybe a) (Maybe b) c
fun = undefined @_ @(Match (Maybe a) (Maybe b) c)

这巧妙地回避了这个不可能的问题。
fun
的结果类型现在推迟到使用时,这是
AllowAmbiguousTypes
的威力/诅咒。现在,
fun@Int@String@Int::String
,通过第一个等式,
fun@Int@String@String::Int
,通过第二个等式,
fun@Int@String@Bool::Bool
,通过第三个等式。无法使此函数在定义处“选择”第三个等式。

请稍候。您隐式声明
a
c
match(可能a)(可能b)c
中不匹配。你怎么知道它们不匹配?没有直接的方法,但是你可以通过使用
(a==c)~'False
作为穷人的不合格约束来获得一些好处:丹尼尔,我写这篇文章的方式多种多样。这一次的效果和一个封闭家族中两条线的尝试一样好,第一条线a与a匹配。我不知道我在说什么或不说什么,我缺乏这种背景。@李耀霞这本书读起来很有趣,谢谢。非常有趣。。。