谢谢我的另一个疑问如何在HList上编写异构列表?的答案,我可以开始使用HList:异构列表,主要是使用API of https://hackage.haskell.org/package/HList-0.5.2.0/docs/Data-HList-HList.html。
现在,我要- 生成同质列表作为HList l -> [e]
hMapOut :: forall f e l. HMapOut f l e => f -> HList l -> [e]
我一直在尝试创建我自己的概念代码证明,但不知道如何正确地做到这一点。
import Data.HList (HList, hBuild, hEnd, hMap, hMapOut)
iA :: [Int]
iA = [1, 2, 3] :: [Int]
iB :: [[Char]]
iB = ["foo", "bar"] :: [[Char]]
iAiB :: HList '[[Int], [[Char]]]
iAiB = hEnd $ hBuild iA iB
flag :: Any -> Bool
flag = \iX -> length iX >= 3 --- ERROR HERE
flags :: HList l -> [e]
flags = \iList ->
iList & hMapOut flag
iBool :: [e]
iBool = flags iAiB
main :: IO ()
main = print iBool这是最简单的例子,就我的目的而言,它需要封装到IO中,无论是哪种方式,它都有相同的错误。
• Couldn't match expected type ‘t0 a0’ with actual type ‘Any’
• In the first argument of ‘length’, namely ‘x’
In the first argument of ‘(>=)’, namely ‘length x’
In the expression: length x >= 3 typecheck(-Wdeferred-type-errors)我认为Any类型是错误的,但我不知道如何键入。建议?
我也做了
flag :: forall (t :: * -> *) a. Foldable t => t a -> Bool
flag = \iX -> length iX >= 3这消除了此函数的错误,但现在又出现了另一个错误
flags :: HList l -> [e]
flags = \iList ->
iList & hMapOut flag --- ERROR HERE作为
• Ambiguous type variables ‘t0’,
‘a0’ arising from a use of ‘hMapOut’
prevents the constraint ‘(Data.HList.HList.HFoldr所以,这似乎是根本的问题。
试过乐趣‘
import Data.HList (HList, hBuild, hEnd, hMap, hMapOut, Fun' (Fun'))
flags :: HList l -> [e]
flags = \iList ->
iList & hMapOut (Fun' flag :: Fun' Foldable Bool)错误:
• Could not deduce: b ~ Bool
from the context: Data.HList.FakePrelude.FunCxt Foldable b
bound by a type expected by the context:
forall b.
Data.HList.FakePrelude.FunCxt Foldable b =>
Data.HList.FakePrelude.FunApp Bool b -> b发布于 2022-03-03 09:54:11
你的第二个版本,flag :: ∀ t a. Foldable t => t a -> Bool,是明智的。但是在HList上映射这一点有点棘手,因为约束没有表单Type -> Constraint,而是带有(Type -> Type) -> Constraint的t应用程序。
由于您似乎不需要支持通用的可折叠容器( FWIW,Foldable-based定义的length is 不管怎样,有点可疑),所以我建议使用班级
flag :: ∀ l. IsList l => l -> Bool
flag = (>=3) . length . toList或者,我们可以使用Foldable签名将Type -> Constraint快速包装到自己的类中:
class HasLength l where gLength :: l -> Int
instance Foldable t => HasLength (t a) where gLength = length
flag :: ∀ l. HasLength l => l -> Bool
flag = (>=3) . gLength现在,这很容易折叠到一个HList上:
flags :: HMapOut (Fun IsList Bool) l Bool
=> HList l -> [Bool]
flags = hMapOut (Fun flag :: Fun IsList Bool)注意,这是Fun,而不是Fun'。后者在这种情况下不起作用(通常也适用于HMapOut),因为函数的输入是多态的,也就是说,无法从输出类型中确定输入类型。
同样,我倾向于定义一个助手,以使这种定义更加方便:
h'MapOut :: ∀ (cxt :: Type -> Constraint) getb l
. HMapOut (Fun cxt getb) l getb
=> (∀ a . (cxt a) => a -> getb) -> HList l -> [getb]
h'MapOut f = hMapOut (Fun f :: Fun cxt getb)然后简单地
flags = h'MapOut @IsList flag完整代码:
{-# LANGUAGE ScopedTypeVariables, UnicodeSyntax
, KindSignatures, ConstraintKinds, RankNTypes
, FlexibleContexts, FlexibleInstances
, AllowAmbiguousTypes, TypeApplications #-}
import Data.HList
import GHC.Exts (IsList(..))
import Data.Kind
flag :: ∀ l. HasLength l => l -> Bool
flag = (>=3) . gLength
h'MapOut :: ∀ (cxt :: Type -> Constraint) getb l
. HMapOut (Fun cxt getb) l getb
=> (∀ a . (cxt a) => a -> getb) -> HList l -> [getb]
h'MapOut f = hMapOut (Fun f :: Fun cxt getb)
flags :: HMapOut (Fun HasLength Bool) l Bool
=> HList l -> [Bool]
flags = h'MapOut @HasLength flag
class HasLength l where gLength :: l -> Int
instance Foldable t => HasLength (t a) where gLength = lengthhttps://stackoverflow.com/questions/71332269
复制相似问题