[英]Haskell type variable not resolving
我有以下代碼片段
class LatticeElement a where
next :: a -> a -- next element
class (Ord a, LatticeElement a) => LatticeDate a where
prev :: a -> a -- prev date
data LatticeSlice d v = forall d v. (LatticeDate d, LatticeElement v) => LatticeSlice{date :: d, slice :: v}
map :: (v -> w) -> LatticeSlice d v -> LatticeSlice d w
map f LatticeSlice{date = d, slice = sl} = LatticeSlice{date = d, slice = f sl}
這會導致編譯錯誤。 現在,據我了解代碼,首先我將LatticeElement
設置為類型類,然后將LatticeDate
設置為LatticeElement
類型清除的特化,要求類型d
是Ord
的實例。
現在我創建LatticeSlice
,並聲明我讀到類似“ LatticeSlice
是類型d
和v
的數據類型,僅限於所有類型d
實例化LatticeDate
和v
實例化LatticeElement
”
錯誤出現在map
的實例化中:
src/Lattice.hs:9:77: error:
• Couldn't match expected type ‘v’ with actual type ‘v1’
‘v1’ is a rigid type variable bound by
a pattern with constructor:
LatticeSlice :: forall d1 v1 d2 v2.
(LatticeDate d2, LatticeElement v2) =>
d2 -> v2 -> LatticeSlice d1 v1,
in an equation for ‘map’
at src/Lattice.hs:9:7-40
‘v’ is a rigid type variable bound by
the type signature for:
Lattice.map :: forall v w d.
(v -> w) -> LatticeSlice d v -> LatticeSlice d w
at src/Lattice.hs:8:1-55
• In the first argument of ‘f’, namely ‘sl’
In the ‘slice’ field of a record
In the expression: LatticeSlice {date = d, slice = f sl}
• Relevant bindings include
sl :: v1 (bound at src/Lattice.hs:9:38)
f :: v -> w (bound at src/Lattice.hs:9:5)
map :: (v -> w) -> LatticeSlice d v -> LatticeSlice d w
(bound at src/Lattice.hs:9:1)
我認為編譯器告訴我它沒有將(v -> w)
中的v
解析為與LatticeSlice dv
中的v
相同的類型。 但是我不知道它為什么要這樣做,或者更重要的是,該怎么辦!
首先, forall d v.
掩蓋了LatticeSlice
的論點。
d1 d2 d2 d2
| | | |
v v v v
data LatticeSlice d v = forall d v. (LatticeDate d, LatticeElement v) => LatticeSlice{date :: d, slice :: v}
^ ^ ^ ^
| | | |
v1 v2 v2 v2
LatticeSlice
的類型證明了這一點
>> :set -fprint-explicit-foralls
>> :t +v LatticeSlice
LatticeSlice
:: forall d1 v1 d2 v2.
(LatticeDate d2, LatticeElement v2) =>
d2 -> v2 -> LatticeSlice d1 v1
值構造函數的參數類型有d2
和v2
與類型構造函數d1
和v1
的參數無關:
instance LatticeDate ()
instance LatticeElement ()
ls :: LatticeSlice d v
ls = LatticeSlice () ()
如果你刪除了你的數據類型攜帶約束的forall
量詞,在這種情況下,我建議再次使用它! 它相當於這個 GADT:
data LatticeSlice d v where
LatticeSlice :: (LatticeDate d, LatticeElement v) => {date :: d, slice :: v} -> LatticeSlice d v
約束阻礙了您的定義, map
在w
參數中不能是參數化的。 僅僅因為v
是LatticeElement
並不意味着w
是。 因此我們必須證明f sl :: w
是一個LatticeElement w
:
map :: LatticeElement w => (v -> w) -> LatticeSlice d v -> LatticeSlice d w
map f LatticeSlice{date = d, slice = sl} = LatticeSlice{date = d, slice = f sl}
這使得它與Functor
( Applicative
, Monad
..) 和Bifunctor
( Biapplicative
, ..) 等基礎設施不兼容。
這是最好的版本,如果您需要晶格約束,您可以將它們添加到在LatticeSlice
上運行的函數中
data LatticeSlice d v = LatticeSlice {date :: d, slice :: v}
deriving stock Functor
instance Bifunctor LatticeSlice where
bimap :: (d -> d') -> (s -> s') -> (LatticeSlice d s -> LatticeSlice d' s')
bimap f g as = bipure f g <<*>> as
instance Biapplicative LatticeSlice where
bipure :: d -> s -> LatticeSlice d s
bipure = LatticeSlice
biliftA2 :: (d1 -> d2 -> d3)
-> (s1 -> s2 -> s3)
-> (LatticeSlice d1 s1 -> LatticeSlice d2 s2 -> LatticeSlice d3 s3)
biliftA2 (·) (×) (LatticeSlice d1 s1) (LatticeSlice d2 s2) =
LatticeSlice (d1 · d2) (s1 × s2)
觀看 Edward Kmett 的Type Classes vs. the World了解更多信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.