Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 使用泛型函数在异构数据结构上映射_Haskell_Hlist - Fatal编程技术网

Haskell 使用泛型函数在异构数据结构上映射

Haskell 使用泛型函数在异构数据结构上映射,haskell,hlist,Haskell,Hlist,我正在进行HList实现,我一直在尝试为它实现map函数。我尝试了很多不同的方法,但每一种方法都会导致与该函数相关的编译器错误 下面是一个示例,说明如何使用一个通用函数将其应用于输入数据结构的所有元素 {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} -- | An input heterogenous data structure recursivePairs :: (Int, (Char, (

我正在进行HList实现,我一直在尝试为它实现
map
函数。我尝试了很多不同的方法,但每一种方法都会导致与该函数相关的编译器错误

下面是一个示例,说明如何使用一个通用函数
将其应用于输入数据结构的所有元素

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

-- | An input heterogenous data structure
recursivePairs :: (Int, (Char, (Bool, ())))
recursivePairs = (1, ('a', (True, ())))

-- | This is how I want to use it
recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool, ())))
recursivePairs' = hMap Just recursivePairs

class HMap f input output where
  hMap :: f -> input -> output

-- | A counterpart of a Nil pattern match for a list
instance HMap f () () where
  hMap _ _ = ()

-- | A counterpart of a Cons pattern match for a list
instance 
  ( HMap f iTail oTail, 
    Apply f iHead oHead ) =>
  HMap f (iHead, iTail) (oHead, oTail) 
  where
    hMap f (head, tail) = (apply f head, hMap f tail)

class Apply f input output where
  apply :: f -> input -> output

instance Apply (input -> output) input output where
  apply = id
由此,我得到以下编译器错误:

No instance for (Apply (a0 -> Maybe a0) Int (Maybe Int))
  arising from a use of `hMap'
The type variable `a0' is ambiguous

有没有办法解决这个问题?如果没有,原因是什么?

问题是,您试图使用具有不同参数的多态函数,但是您的
Apply
实例使用一个函数(单类型)。您可以通过多种方式轻松解决此问题

data JustIfy = JustIfy
instance Apply JustIfy a (Maybe a) where
  apply _ = Just

recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool, ())))
recursivePairs' = hMap JustIfy recursivePairs
可以很好地处理代码

编辑:对于同一件事,更通用的方法是(需要
RankNTypes

或者,如果您正在使用GHC的最新版本,并且愿意启用更多扩展

newtype Univ' c f = Univ' (forall x. c x => x -> f x)
instance c x => Apply (Univ' c f) x (f x) where
  apply (Univ' f) x = f x

class All x
instance All x

recursivePairs' :: (Maybe Int, (Maybe Char, (Maybe Bool, ())))
recursivePairs' = hMap (Univ' Just :: Univ' All Maybe) recursivePairs
这很好,因为它允许您在映射的函数中包含“show”

对于一个更通用的解决方案,请查看它,它允许您在值级别编写代码,然后自动神奇地推断出适当的类型级别程序。不幸的是,在这一点上,Oleg的解决方案相当陈旧,并且使用了我并不特别喜欢的LC的名义实现。我一直在考虑如何做得更好,但可能会推迟,直到类型家庭实现决定性的平等


我的观点是,HLists现在应该使用GADT和数据种类,而不是元组。类型族比函数依赖更可取,但由于它们缺乏可判定的相等性,因此目前受到的限制更大

尽管下面的内容并不能完全回答这个问题(因此我不会接受),但它确实解决了映射结构的问题,而不需要为应用程序函子提供任何额外的实例:

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

import Control.Applicative

main = do
  print $ (hPure recursivePairs :: (Maybe Int, (Maybe Char, (Maybe Bool, ()))))
  print $ (hPure recursivePairs :: ([Int], ([Char], ([Bool], ()))))

recursivePairs :: (Int, (Char, (Bool, ())))
recursivePairs = (1, ('a', (True, ())))

class HPure input output where
  hPure :: input -> output

instance HPure () () where
  hPure _ = ()

instance  
  ( Applicative f, 
    HPure iTail oTail ) => 
  HPure (iHead, iTail) (f iHead, oTail) 
  where hPure (iHead, iTail) = (pure iHead, hPure iTail)
产出:

(Just 1,(Just 'a',(Just True,())))
([1],("a",([True],())))

我认为问题在于类型系统没有意识到您在每个后续应用程序上使用不同的具体类型实例化
,因为您对
hMap
的定义一直在重复使用相同的
f
。第一次应用时,类型是
Int->Maybe Int
,第二次应用时,类型是
Char->Maybe Char
。然而,我仍然不确定如何修复它。@GabrielGonzalez是的,这正是问题所在。如果您将fundep
|input-output->f
添加到
Apply
类中,错误消息将表明它正在查找实例,例如
(Bool->maybool)Char(Maybe Char)
。我正在考虑在类型级别上使用来断开
f
的两种用法,但这感觉不是很自然,依赖
Typeable
也不是很吸引人。谢谢。你说有多种方法可以解决这个问题-你能详细说明一下吗?我正在寻找一个最佳的解决方案,因此不需要以任何方式坚持提供的代码,这只是一个抽象的例子。有没有一种方法可以解决这个问题,而不必为我想与
hMap
一起使用的每个函数声明特定实例?@NikitaVolkov我添加了更多的通用解决方案
(Just 1,(Just 'a',(Just True,())))
([1],("a",([True],())))