gpt4 book ai didi

haskell - 一起使用 makeLenses、类约束和类型同义词

转载 作者:行者123 更新时间:2023-12-03 22:24:11 24 4
gpt4 key购买 nike

我对 Haskell 很陌生,想使用 makeLenses来自 Control.Lens和类约束与类型同义词一起使我的函数类型更紧凑(可读?)。

我试图提出一个最小的虚拟示例来演示我想要实现的目标,并且该示例没有其他目的。

如果您对上下文感兴趣,在这篇文章的末尾,我添加了一个更接近我原始问题的示例。

最小示例

例如,假设我定义了以下数据类型:

data State a = State { _a :: a
} deriving Show

,我也为此制作镜头:
makeLenses ''State

为了对类型参数 a 实现类约束由类型构造函数使用 State我使用智能构造函数:
mkState :: (Num a) =>  a -> State a
mkState n = State {_a = n}

接下来,假设我有许多类型签名与此类似的函数:
doStuff :: Num a => State a -> State a
doStuff s = s & a %~ (*2)

这一切都按预期工作,例如:
test = doStuff . mkState $ 5.5 -- results in State {_a = 11.0}

问题

我尝试使用以下类型同义词:
type S = (Num n) => State n -- Requires the RankNTypes extensions

, 和...一起:
{-# LANGUAGE RankNTypes #-}

, 试图简化 doStuff 的类型签名:
doStuff :: S -> S

,但这会产生以下错误:
Couldn't match type `State a0' with `forall n. Num n => State n'
Expected type: a0 -> S
Actual type: a0 -> State a0
In the second argument of `(.)', namely `mkState'
In the expression: doStuff . mkState
In the expression: doStuff . mkState $ 5.5
Failed, modules loaded: none.

问题

我目前对 Haskell 的了解不足以理解导致上述错误的原因。我希望有人可以解释导致错误的原因和/或建议其他方法来构造类型同义词或为什么这种类型同义词是不可能的。

背景

我原来的问题看起来更接近这个:
data State r = State { _time :: Int
, _ready :: r
} deriving Show

makeLenses ''State

data Task = Task { ... }

这里我要强制执行 _ready 的类型是 Queue 的一个实例类使用以下智能构造函数:
mkState :: (Queue q) => Int -> q Task -> State (q Task)
mkState t q = State { _time = t
, _ready = q
}

我还有许多类型签名与此类似的函数:
updateState :: Queue q => State (q Task) -> Task -> State (q Task)
updateState s x = s & ready %~ (enqueue x) & time %~ (+1)

我想使用类型同义词 S能够重写此类函数的类型,例如:
updateState :: S -> Task -> S

,但与第一个最小示例一样,我不知道如何定义类型同义词 S或者是否有可能。

也许尝试简化类型签名并没有真正的好处?

相关阅读

我已阅读有关 SO 的以下相关问题:
  • Class constraints for data records
  • Are type synonyms with typeclass constraints possible?

  • 这也可能是相关的,但鉴于我目前对 Haskell 的理解,我无法真正理解所有这些:
  • Unifying associated type synonyms with class constraints

  • 跟进

    自从我有机会做一些 Haskell 以来已经有一段时间了。感谢@bheklilr,我现在设法引入了一个类型同义词,只是为了遇到下一个我仍然无法理解的类型错误。我已经发布了以下后续问题 Type synonym causes type error关于新类型错误。

    最佳答案

    由于 . 的组合,您会看到该错误。运算符和您对 RankNTypes 的使用.如果你把它从

    test = doStuff . mkState $ 5.5


    test = doStuff $ mkState 5.5

    甚至
    test = doStuff (mkState 5.5)

    它会编译。为什么是这样?查看类型:
    doStuff :: forall n. Num n => State n -> State n
    mkState :: Num n => n -> State n

    (doStuff) . (mkState) <===> (forall n. Num n => State n -> State n) . (Num n => n -> State n)

    希望括号有助于在这里清楚, n来自 forall n. Num n ...对于 doStuff是与 Num n => ... 不同的类型变量对于 mkState因为 forall的范围仅延伸到括号的末尾。所以这些函数实际上不能组合,因为编译器将它们视为单独的类型! $ 实际上有特殊的规则。专门用于使用 ST 的运算符monad 正是出于这个原因,所以你可以这样做 runST $ do ... .

    您可以使用 GADT 更轻松地完成您想要的事情,但我不相信 lens ' TemplateHaskell将适用于 GADT 类型。但是,在这种情况下,您可以很容易地编写自己的代码,所以没什么大不了的。

    进一步的解释:
    doStuff . mkState $ 5.5

    非常不同
    doStuff $ mkState 5.5

    在第一个中, doStuff说所有 Num类型 n ,其类型为 State n -> State n , 而 mkState说一些 Num类型 m ,其类型为 m -> State m .这两种类型并不相同,因为“对于所有”和“对于某些”量化(因此 ExistentialQuantification ),因为组合它们意味着对于某些 Num m你可以生产所有 Num n .

    doStuff $ mkState 5.5 ,你有相当于
    (forall n. Num n => State n -> State n) $ (Num m => State m)

    注意 $ 之后的类型不是函数,因为 mkState 5.5被完全应用。所以这是可行的,因为对于所有 Num n你可以做 State n -> State n , 你提供了一些 Num m => State m .这很直观。同样,这里的区别在于组合与应用。您不能将适用于某些类型的函数与适用于所有类型的函数组合在一起,但您可以将值传递给适用于所有类型的函数(“所有类型”在此表示 forall n. Num n => n)。

    关于haskell - 一起使用 makeLenses、类约束和类型同义词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30582583/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com