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匹配。我不知道我在说什么或不说什么,我缺乏这种背景。@李耀霞这本书读起来很有趣,谢谢。非常有趣。。。