【问题标题】:Haskell: declaring a type for a "where" function that refers to variables in the higher level function [duplicate]Haskell:为“where”函数声明一个类型,该函数引用更高级别函数中的变量[重复]
【发布时间】:2016-12-15 20:18:55
【问题描述】:

我胡闹,在 Haskell 中定义了一个for 函数,如下所示。

for :: (Ord i, Num i) => (i, i, i) -> b -> (i -> b -> b) -> b
for  (init, incr, end) initState bodyFn = for' (init, initState) bodyFn 

  where
  -- for' :: (Ord i, Num i) => (i, b) -> (i -> b -> b) -> b
  for' (index, state) bodyFn | if incr > 0 then index >= end else index <= end = state
  for' (index, state) bodyFn = for' (index + incr, bodyFn index state) bodyFn 

效果很好。

> for (1, 1, 10) 0 (\i b -> i+b)
45

我想声明where 函数的类型。 (如您所见,它已被注释掉。)当我删除注释标记时,我收到此错误消息。

Couldn't match expected type ‘i1’ with actual type ‘i’
  ‘i’ is a rigid type variable bound by
    the type signature for:
      for :: forall i b.
             (Ord i, Num i) =>
             (i, i, i) -> b -> (i -> b -> b) -> b
    at while.hs:5:8
  ‘i1’ is a rigid type variable bound by
    the type signature for:
      for' :: forall i1 b1.
              (Ord i1, Num i1) =>
              (i1, b1) -> (i1 -> b1 -> b1) -> b1
    at while.hs:9:11
• In the second argument of ‘(>=)’, namely ‘end’
  In the expression: index >= end
  In the expression: if incr > 0 then index >= end else index <= end
• Relevant bindings include
    bodyFn :: i1 -> b1 -> b1 (bound at while.hs:10:23)
    index :: i1 (bound at while.hs:10:9)
    for' :: (i1, b1) -> (i1 -> b1 -> b1) -> b1 (bound at while.hs:10:3)
    bodyFn :: i -> b -> b (bound at while.hs:6:34)
    end :: i (bound at while.hs:6:19)
    incr :: i (bound at while.hs:6:13)

我猜这个问题与for' 函数将其变量之一与for 函数中的变量进行比较这一事实有关——并且还将其变量之一添加到来自for 函数。它们应该属于同一类型。有没有办法这么说?或者有没有其他方法来声明for'函数的类型?

谢谢。

附:我知道我可以将for' 函数声明为顶级函数并将相关变量传递给它,但我想知道是否有办法使用这种结构编写有效的声明。

P.P.S 基本上同样的问题被问到here,但答案是去掉嵌套函数的声明。有什么方法可以写一个有效的吗?

【问题讨论】:

  • 刚性类型变量不匹配的答案解决了这个问题。谢谢

标签: haskell


【解决方案1】:

感谢jberryman,给Mismatch of rigid type variables的答案解决了这个问题。以下代码有效。 (注意bodyFn也不需要传递。)

{-# LANGUAGE ScopedTypeVariables #-}

for :: forall i b. (Ord i, Num i) => (i, i, i) -> b -> (i -> b -> b) -> b
for  (init, incr, end) initState bodyFn = for' (init, initState)  

  where
  for' :: (Ord i, Num i) => (i, b) -> b
  for' (index, state) | if incr > 0 then index >= end else index <= end = state
  for' (index, state) = for' (index + incr, bodyFn index state)  

【讨论】:

  • 你不需要在for'中再次写出Ord iNum i
  • 希望for' 中不必要的元组构造和解构将得到优化。然而,它是单调的,代码的读者会偶然发现它并问自己:为什么我们需要在这里传递一个元组?
猜你喜欢
  • 1970-01-01
  • 2022-08-24
  • 2020-04-05
  • 2017-07-08
  • 2017-04-15
  • 1970-01-01
  • 2014-05-25
  • 2017-05-27
相关资源
最近更新 更多