Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
元组内的Haskell箭头_Haskell_Functional Programming_Tuples_Arrows - Fatal编程技术网

元组内的Haskell箭头

元组内的Haskell箭头,haskell,functional-programming,tuples,arrows,Haskell,Functional Programming,Tuples,Arrows,我想包装一个元组,其中包含一个箭头和一个描述箭头的字符串。如果我使用函数(而不是箭头)执行此操作,则以下操作与预期的一样: funTimes10 = (*10) describe10 = "times 10" tuple10 :: (Num b) => ((b -> b), String) tuple10 = (,) funTimes10 describe10 我可以使用fst访问函数,使用snd我可以获得函数的描述字符串 但是,如果我用箭头交换函数,如下所示: aTuple10

我想包装一个元组,其中包含一个箭头和一个描述箭头的字符串。如果我使用函数(而不是箭头)执行此操作,则以下操作与预期的一样:

funTimes10 = (*10)
describe10 = "times 10"

tuple10 :: (Num b) => ((b -> b), String)
tuple10 = (,) funTimes10 describe10
我可以使用
fst
访问函数,使用
snd
我可以获得函数的描述字符串

但是,如果我用箭头交换函数,如下所示:

aTuple10 :: (Arrow a, Num b) => (a b b, String)
aTuple10 = (,) (arr funTimes10) describe10
  • fst
    仍然有效并返回我的箭头,但是
  • 我没有得到任何带有
    snd
    的描述字符串
我只收到以下错误消息:

Ambiguous type variable `a0' in the constraint:
  (Arrow a0) arising from a use of `aTuple10'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `snd', namely `aTuple10'
In the expression: (snd aTuple10)
In an equation for `it': it = (snd aTuple10)

为什么我会出现这个错误,我应该做些什么来避免它

让我们看看
snd的类型:

snd :: (foo, x) -> x
(为了清晰起见,我重命名了类型变量)

类型说明的是,对于类型为
foo
x
的元组,返回类型为
x
的内容。这里需要知道的重要一点是,虽然价值体系。Haskell中的运行时是惰性的,Haskell的类型系统是严格的,这意味着在调用
snd
之前必须知道
foo
x
的类型

在第一种情况下,当您只有一个
numb=>(b->b,String)
时,调用
snd
将使
b
变得模棱两可,因为您没有在任何地方提到它的具体类型,并且它不能从返回类型推断出来,因为
foo~b
x
不同。换句话说:因为
(b,b)
可以是任何数字类型的元组,而类型检查器无法确定是哪一个,所以它是不明确的。这里的诀窍是,我们将引入Haskell的默认规则,该规则规定,如果数值类型不明确,则应默认为
Integer
。如果您使用
-Wall
打开了警告,它会说这正在发生。因此,我们的类型变成
(Integer->Integer,String)
,并且可以调用
snd

然而,在第二种情况下,我们仍然能够通过默认规则推断
b
,但是
a
没有默认的
箭头,所以我们被卡住了!必须明确指定要继续的箭头!您可以先在其他地方使用
aTuple10
的值来执行此操作:

let bla = aTuple10  -- We do this because `aTuple10` can have type variables, but `bla` cannot (by default)
fst bla (23 :: Int) -- This fixes the type of `bla`, so that `a ~ (->)` and `b ~ Int`
print $ snd bla     -- So the arrow isn't ambiguous here
。。。或者,您可以只指定所需的类型:

print $ snd (aTuple10 :: (Int -> Int, String))

PS如果您想更改不明确数字的默认类型,可以帮助您解决。

我尝试编译以下内容:

import Control.Arrow

funTimes10 = (*10)
describe10 = "times 10"

tuple10 :: (Num b) => ((b -> b), String)
tuple10 = (,) funTimes10 describe10

aTuple10 :: (Arrow a, Num b) => (a b b, String)
aTuple10 = (,) (arr funTimes10) describe10
但我明白了:

Could not deduce (b ~ Integer)
from the context (Arrow a, Num b)
  bound by the type signature for
             aTuple10 :: (Arrow a, Num b) => (a b b, String)
  at D:\dev\haskell\arr_tuple.hs:10:1-42
  `b' is a rigid type variable bound by
      the type signature for
        aTuple10 :: (Arrow a, Num b) => (a b b, String)
      at D:\dev\haskell\arr_tuple.hs:10:1
Expected type: b -> b
  Actual type: Integer -> Integer
In the first argument of `arr', namely `funTimes10'
In the first argument of `(,)', namely `(arr funTimes10)'

所以,我猜您需要决定要使用哪个arrow实例。也就是说,您可能需要使用注释指定
arr funTimes
的具体类型。

此处的错误与当前问题完全无关。它出现是因为您忘记了
funTimes10
的类型签名。请查看。@dflemstr我的回答是否与原始问题存在问题?我没有忘记一个打字签名,它不在原来的帖子里。虽然我没有描述潜在的问题(因为我没有看到),但我认为不值得对我的答案投反对票。我认为OP只是复制了他的函数的定义,以证明他在使用哪种值。他有一个多态的
funTimes10
,否则他会得到一个不同的错误。真烦人。人们期望类型系统能够得出结论,即
sndatuple10
具有类型
String
;这会被认为是实现中的一个bug吗?Haskell 2010肯定没有具体说明这种行为。有人可能会说,如果实现不知道第一件事的类型,它就不知道第二件事在内存中的位置,但是因为我们在这里处理的是装箱元组,所以应该总是有两个指针,因此,无论第一个元素的类型如何,第二个元素都很容易定位;foo::Boolish a=>(a,b)->b;foo(a,b)=如果toBool a那么b else undefined
是可以想象的,因此函数的结果可能取决于一个不明确的参数。在那种情况下,
snd
的特殊外壳会很奇怪。你救了我的命,
(23::Int)
魔术变魔术了!谢谢