在以下示例中:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE PolyKinds #-}
newtype A a b = A (a, b)
type family F (x :: k) = (r :: k) | r -> x
type instance F (A a) = A a
type instance F (A a b) = A a b
Run Code Online (Sandbox Code Playgroud)
在我目前的理解中,第一个类型实例处理*->*kind,而第二个实例处理*.
因此,即使我使用相同的 newtype A,我也看不到任何注入性违规风险,因为绝对没有A a匹配 a ,A a b因为它们甚至没有相同的类型。
然而 GHC 8.6.5 抱怨这两种类型的实例违反了注入性,但这是为什么呢?有解决方法吗?
我们知道,fmap“签名是(a -> b) -> f a -> f b其中f的一个Functor。
为了尽可能地通用和更好地分解因子代码,人们可能希望将“事物列表”映射到另一个可能不同的“事物列表”。凭直觉,我不明白为什么它不应该或不可能。
我正在寻找的功能gmap与该功能具有相同的功能,fmap但具有该签名gmap :: (a -> b) -> (f a) -> (g b),在该功能中,我允许到达和离开容器有所不同。
我不确定这在一般情况下where f和gare 是否有意义Functors,但是Traversable假设我最感兴趣的是遍历数据,那么“事物列表”的想法在本质上听起来更像是课堂上所捕获的。
所以也许签名应该是gmap :: (Traversable f, Traversable g) => (a -> b) -> (f a) -> (g b)。
即使g具有不同的性质f,它仍然可以从左到右遍历,因此仍然觉得应该能够将的第k个被访问元素映射f到的第k个被访问元素g。
假设我的想法没有错,Haskell中是否有这样的功能?
从本质上讲,我的问题是,您将如何以最简洁,最优雅的方式从Haskell中的一个类似列表的事物转换为另一个?
在这里查看http://hackage.haskell.org/package/vector-0.12.0.3/docs/Data-Vector-Mutable.html 可以看到读取类型为:
read :: PrimMonad m => MVector (PrimState m) a -> Int -> m a
Run Code Online (Sandbox Code Playgroud)
由于读取操作不会修改向量,所以我的主要问题是为什么不这样做:
read :: PrimMonad m => MVector (PrimState m) a -> Int -> a
Run Code Online (Sandbox Code Playgroud)
可变向量的长度在向量上也做不可变的事情,其类型 MVector s a -> Int看起来很正常。不是PrimMonad m => MVector (PrimState m) a -> m Int。那么,为什么在读取和长度之间做出设计选择上的差异,因为它们都是向量上的不变操作?
现在我考虑一下,以某种方式读取返回的单元格是对向量内部单元格的引用,而不是其数据的副本吗?如果是这样,我怎么能以可变的向量很好且廉价地获得对第n个元素的不变访问?我正在学习haskell,但不太了解细节。
谢谢,
因此,假设您有两个这样定义的类型类:
{-# LANGUAGE MultiParamTypeClasses #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
Run Code Online (Sandbox Code Playgroud)
然后,您想通过使用f和g以一般方式定义新函数h。
h a = g (f a)
Run Code Online (Sandbox Code Playgroud)
我们知道此函数具有类型,a -> b因此c在其中隐含。我想把它留给的实现者f以及可能是g什么c。Haskell抱怨这句话c含糊不清。
然后根据错误提示,我打开了该扩展名:
{-# LANGUAGE AllowAmbiguousTypes #-}
Run Code Online (Sandbox Code Playgroud)
现在可以了!真好
我相信通常作为一种好的软件工程实践,我想写出我的函数的明确规范,以告诉编译器我期望我的函数应具有的行为。这样以后的编译器就可以抱怨我不尊重我的设置。
因此,我想在其之前添加函数的类型:
h :: (F a c, G c b) => a -> b
h a = g (f a)
Run Code Online (Sandbox Code Playgroud)
现在,类型歧义错误再次出现...为什么?
总结一下为什么Haskell在下面的代码段中会抱怨这一点?即使显式启用了AllowAmbiguousTypes。如何在保留显式函数类型定义的同时对其进行修复?我知道删除该函数的类型定义可以解决该问题,但是我不想对事物进行低估。
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE …Run Code Online (Sandbox Code Playgroud) In Haskell I find it difficult to completely grasp the purpose of a kind system, and what it truly adds to the language.
I understand having kinds adds safety.
For example consider fmap :: (a -> b) -> f a -> f b vs a monokinded version of it fmap2 :: (a -> b) -> p -> q.
My understanding is that, thanks to the kind system, I can specify beforehand with higher detail what the shape of the …
为了澄清我的问题,让我以或多或少等效的方式重新表述它:
为什么 Haskell 中有超类/类继承的概念?导致这种设计选择的历史原因是什么?例如,为什么拥有一个没有类层次结构、只有彼此独立的类型类的基础库会如此糟糕?
在这里我将揭露一些让我想问这个问题的随机想法。我目前的直觉可能不准确,因为它们是基于我目前对 Haskell 的理解,这并不完美,但它们在这里......
对我来说,为什么 Haskell 中存在类型类继承并不明显。我觉得这有点奇怪,因为它造成了概念上的不对称。通常在数学中,概念可以从不同的角度来定义,我不一定想赞成如何定义它们的顺序。好吧,证明事物应该有一定的顺序,但是一旦定理和结构存在,我宁愿将它们视为可用的独立工具。
Moreover one perhaps not so good thing I see with class inheritance is this: I think a class instance will silently pick a corresponding superclass instance, which was probably implemented to be the most natural one for that type. Let's consider a Monad viewed as a subclass of Functor. Maybe there could be more than one way to define a Functor on some type that also happens to be a …
我最近意识到这一点:
一方面:
在类标头上指定的约束必须在该类的实例上再次指定,但在其他地方将该类用作约束的任何使用都不需要重新导入类约束。他们暗自满意。
class (Ord a) => ClassA a where methodA :: a -> Bool -- i decided to put constraint (Ord a) in the class header
instance (Ord a) => ClassA a where methodA x = x <= x -- compiler forces me to add (Ord a) => in the front
Run Code Online (Sandbox Code Playgroud)
class OtherClassA a where otherMethodA :: a -> Bool
instance (ClassA a) => OtherClassA a where otherMethodA x = x <= x && methodA x -- i don't …Run Code Online (Sandbox Code Playgroud) 假设我有一种类型l :: * -> * -> *,所以我需要应用 2 种类型a,并b获得一个简单的类型l a b。
如何将类型映射l :: * -> * -> *到新类型m(l) :: * -> * -> *,其中的m(l) b a含义与l a bfor each相同a,b?这里a,b不是常数。是否可以?这么想有错吗?
说你有这个功能
import Control.Monad
import Control.Monad.ST
import Data.STRef
f :: (Num a, Ord a) => STRef s a -> ST s ()
f i = loop
where
loop = do
_i <- readSTRef i
writeSTRef i (_i - 1)
when (_i > 1) loop
Run Code Online (Sandbox Code Playgroud)
inloop的主体,i被隐式定义,因为它是来自 的参数f。但是我在给loop. Hie 告诉我它应该是ST s (),所以我写loop :: ST s ()了上面loop的定义。
但是 ghc 抱怨它无法将sfromloop与sfrom匹配f。由于loop没有参数,它 …
haskell ×9
typeclass ×3
type-kinds ×2
constraints ×1
functor ×1
polykinds ×1
signature ×1
traversal ×1
vector ×1