感謝您回答我的其他問題 - 如何在 HList 上撰寫異構串列?,我可以開始使用HList: Heterogeneous lists ,主要使用https://hackage.haskell.org/package/HList-0.5.2.0/docs/Data-HList-HList.html的 API
現在,我想要 -生成同質串列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
uj5u.com熱心網友回復:
您的第二個版本flag :: ? t a. Foldable t => t a -> Bool是明智的。但是將它映射到 HList 有點棘手,因為約束沒有 form Type -> Constraint,而是t使用 a (Type -> Type) -> Constraint。
由于您似乎不需要支持通用可折疊容器(并且 FWIW 的Foldable基于 - 的定義無論如何length有點可疑)我建議改為使用IsList該類:
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 = length
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/437094.html
標籤:哈斯克尔
