我有這個 Haskell 代碼片段:
{-# LANGUAGE InstanceSigs #-}
module LatticePoint
where
import Data.List
data (Eq v) => LatticePoint v = LatticePoint{prob::Double, value::v}
instance Functor LatticePoint where
fmap :: (Eq a, Eq b) => (a -> b) -> LatticePoint a -> LatticePoint b
fmap f lp = LatticePoint {prob = prob lp, value = f $ value lp}
編譯時出現以下錯誤,我不明白
src/LatticePoint.hs:12:14: error:
? No instance for (Eq a)
Possible fix:
add (Eq a) to the context of
the type signature for:
fmap :: forall a b. (a -> b) -> LatticePoint a -> LatticePoint b
? When checking that instance signature for ‘fmap’
is more general than its signature in the class
Instance sig: forall a b.
(Eq a, Eq b) =>
(a -> b) -> LatticePoint a -> LatticePoint b
Class sig: forall a b.
(a -> b) -> LatticePoint a -> LatticePoint b
In the instance declaration for ‘Functor LatticePoint’
|
12 | fmap :: (Eq a, Eq b) => (a -> b) -> LatticePoint a -> LatticePoint b
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我想要實作的是將 LatticePoint 限制為作為 Eq 實體的任何型別 v,并使 LatticePoint 成為 Functor 的實體。
uj5u.com熱心網友回復:
你LatticePoint的不是Functor. AFunctor被定義為“對于每一對型別a和b,我可以將一個函式提升a -> b為一個函式f a -> f b”。您不能提供僅適用于少數型別或某些但不是全部的實體。這與Set不是仿函式的原因相同,因為對其進行Ord的所有重要操作都需要元素型別。
在我們可以使用 的替代方法之前Functor,我們實際上需要從這篇文章的評論部分獲得一些建議。正如所指出的,在 Haskell 中,通常不約束資料型別本身,而僅約束作用于它的所有函式(允許資料型別約束的特性在很大程度上被認為是錯誤特性,不鼓勵使用它)。因此,與其將Eq約束放在data行中,不如將行保留data一個普通宣告并約束每個接受或產生LatticePoint.
這是因為,如果您直接約束資料型別,那么說for each甚至沒有意義,這使得推理型別變得更加困難(每次您想在任何背景關系中提及您的型別時,您實際上都需要附上正確性證明)。但是,如果型別對每個型別都進行了良好定義,但恰好對其中一些型別來說是無用且不可構造的,那么推理我們的型別會容易得多。所以我假設我們的宣告是LatticePoint aaLatticePoint aa
data LatticePoint v = LatticePoint{prob::Double, value::v}
我們可以用MonoFunctor. MonoFunctor提供了一個更弱的約束。它說“給定我們容器的'元素型別'的一些定義,我可以將元素上的函式提升到容器型別上的函式”。至關重要的是,我們從未說過它必須適用于所有型別,僅適用于容器認為是有效“元素”的型別。
type instance Element (LatticePoint a) = a
現在我們可以撰寫我們的MonoFunctor實體了。
instance Eq a => MonoFunctor (LatticePoint a) where
omap :: (a -> a) -> LatticePoint a -> LatticePoint a
omap f latticePoint = ...
你會在這里注意到一件事:我們的函式必須映射 froma到a。它不能映射到不同的目標型別,即使源和目標都是Eq. 這只是 的限制MonoFunctor,而且我不知道有任何型別類允許MonoFunctor-style 類約束并允許非自同態的映射。
uj5u.com熱心網友回復:
將我的評論轉換為答案,您通常會將約束推遲到在值需要約束的背景關系中使用 的函式。這讓您可以定義.LatticePointEqfmap
module LatticePoint
where
import Data.List
data LatticePoint v = LatticePoint{prob::Double, value::v}
instance Functor LatticePoint where
fmap :: (a -> b) -> LatticePoint a -> LatticePoint b
fmap f lp = LatticePoint {prob = prob lp, value = f $ value lp}
foo :: Eq a => LatticePoint a -> Whatever
foo lp = ...
如果您考慮一下,資料結構本身并不關心是否value可以比較是否相等,只關心使用該資料結構的函式。
作為一個具體的例子,考慮一個(==)自身的定義:
instance Eq a => Eq (LatticePoint a) where
(LatticePoint p1 v1) == (LatticePoint p2 v2) = p1 == p2 && v1 == v2
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/478651.html
上一篇:函式回傳值的類實體選擇
