考虑以下3个Haskell文件
HList.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
module HList where
data HList :: (k -> *) -> [k] -> * where
Nil :: HList f '[]
(:&) :: !(f x) -> HList f xr -> HList f (x ': xr)
Snd.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module Snd where
import HList
hmap :: forall f g xs. (forall x. f x -> g x) -> HList f xs -> HList g xs
hmap f = go
where
go :: HList f xs' -> HList g xs'
go Nil = Nil
go (x :& xs) = f x :& go xs
type family Snd x where
Snd '(a, b) = b
type family MapSnd xs where
MapSnd '[] = '[]
MapSnd (y ': ys) = Snd y ': MapSnd ys
hmap2 :: forall f g (xs :: [(*,*)]). (forall x. f x -> g (Snd x)) -> HList f xs -> HList g (MapSnd xs)
hmap2 f = go
where
go :: HList f xs' -> HList g (MapSnd xs')
go Nil = Nil
go (x :& xs) = f x :& go xs
NoSnd.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
module NoSnd where
import HList
hmap :: forall f g xs. (forall x. f x -> g x) -> HList f xs -> HList g xs
hmap f = go
where
go :: HList f xs' -> HList g xs'
go Nil = Nil
go (x :& xs) = f x :& go xs
type family MapSnd xs where
MapSnd '[] = '[]
MapSnd ('(_, y) ': ys) = y ': MapSnd ys
hmap2 :: forall f g (xs :: [(*,*)]). (forall x a b. (x ~ '(a, b)) => f x -> g b) -> HList f xs -> HList g (MapSnd xs)
hmap2 f = go
where
go :: HList f xs' -> HList g (MapSnd xs')
go Nil = Nil
go (x :& xs) = f x :& go xs
编译Snd.hs
有效,但编译NoSnd.hs
会给出
NoSnd.hs:27:20: error:
• Could not deduce: x ~ '(a0, x0) arising from a use of ‘f’
from the context: xs' ~ (x : xr)
bound by a pattern with constructor:
:& :: forall k (a :: k -> *) (x :: k) (xr :: [k]).
a x -> HList a xr -> HList a (x : xr),
in an equation for ‘go’
at NoSnd.hs:27:9-15
‘x’ is a rigid type variable bound by
a pattern with constructor:
:& :: forall k (a :: k -> *) (x :: k) (xr :: [k]).
a x -> HList a xr -> HList a (x : xr),
in an equation for ‘go’
at NoSnd.hs:27:9
• In the first argument of ‘(:&)’, namely ‘f x’
In the expression: f x :& go xs
In an equation for ‘go’: go (x :& xs) = f x :& go xs
• Relevant bindings include x :: f x (bound at NoSnd.hs:27:9)
Snd.hs
和NoSnd.hs
之间的区别在于,在后者中,我尝试直接解构类型,而不是定义类型族Snd
。这发生在两个地方:MapSnd
的定义和({1}}的参数类型。
这两个问题是:有人可以解释类型错误;有没有办法在不定义hmap2
类型系列的情况下编写hmap2
?
谢谢。
答案 0 :(得分:4)
声明
exists a. x ~ '(a, b)
略强于声明
b ~ Snd x
例如,给定
type family Any :: (*, *) where {}
结束
是有效的Snd Any ~ Snd Any
但结论
无效exists a. Any ~ '(a, Snd Any)
因为Any
并未与其他任何内容统一。
您有HList
个按类型(*,*)
索引的内容,但您不知道每个元素实际上都有'(a,b)
形式的类型,所以你不能将证明证明传递给你给予的功能。现在,如果您有一个不太多态的列表,其中元素类型以已知方式编入索引,那么您可以对元素进行模式匹配以获得所需内容。但这不是你所拥有的,而且它不那么通用和有用。使用当前(工作)公式,传递的函数负责计算它需要了解的有关索引结构的任何信息。但那完全没问题;它比你更了解f
的结构。拿你的奖金然后去!