Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.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';s Cast运算符_Haskell - Fatal编程技术网

理解Haskell';s Cast运算符

理解Haskell';s Cast运算符,haskell,Haskell,假设我们已经导入了Data.Typeable,其中包含cast::(Typeable a,Typeable b)->a->Maybe b 考虑一下 > cast 'n' :: Maybe Char Just 'n' 然而 我理解上述内容,但这似乎只是一个微不足道的例子。它没有揭示为什么有人需要使用cast操作符(据我所知) 问题:是否有一个使用cast的示例,它真正地将值的类型从一种类型“更改”为另一种类型?我能想到的最接近的例子(实际上在GHCi中不起作用)是将7的类型从Integer

假设我们已经导入了
Data.Typeable
,其中包含
cast::(Typeable a,Typeable b)->a->Maybe b

考虑一下

> cast 'n' :: Maybe Char
Just 'n'
然而

我理解上述内容,但这似乎只是一个微不足道的例子。它没有揭示为什么有人需要使用
cast
操作符(据我所知)

问题:是否有一个使用
cast
的示例,它真正地将值的类型从一种类型“更改”为另一种类型?我能想到的最接近的例子(实际上在GHCi中不起作用)是将
7
的类型从
Integer
更改为
Double

> cast 7 :: Maybe Double
Just '7' -- this doesn't work, as 7 is typed as a Integer above; instead GHCi returns Nothing
是否有使用cast真正“改变”值类型的例子

简单的答案是否定的。但是,可能有一种情况,你不知道你的类型,因为它被量词“存在”所“隐藏”。下面是一个例子:

{-# LANGUAGE ExistentialQuantification #-}

import Data.Typeable
import Data.Maybe

data Foo = forall a . Typeable a => Foo a

main = print . catMaybes . map (\(Foo x) -> cast x :: Maybe Bool) $ xs
  where
    xs = [Foo True, Foo 'a', Foo "str", Foo False]
输出将是:

[True,False]

Typeable
类的目的是允许您在不知道数据的确切类型时处理数据。
cast
运算符的目的是检查某些数据是否具有特定类型,如果是,则允许您将其作为该类型使用。这一切都是关于对数据的类型签名进行处理。实际值根本不会改变


如果要更改某些数据的值,这不是强制转换,而是转换。各种各样的功能都可以做到这一点。例如,
from Integral
将作为
Integral
实例的某个内容转换为其他内容。(例如,
Int
Double
)这不是强制转换的目的。

假设您想要实现一个函数,该函数在所有值上充当标识函数,除了整数,它应该充当后续函数

在Python等非类型化语言中,这很简单:

>>定义f(x):
...   如果类型(x)==int:
...     返回x+1
...   其他:
...     返回x
... 
>>>f(42)
43
>>>f(“qwerty”)
“qwerty”
即使在Java中,这也是可行的,即使它需要一些强制转换:

与该类型关联的静态

但是,如果我们可以在类型
a
上添加
Typeable
约束,则可以:

f :: forall a. Typeable a => a -> a
f x = case cast x :: Maybe Int of
   Nothing -> x
   Just n  -> case cast (n+1) :: Maybe a of
      Nothing -> x
      Just y -> y
第一个
cast
a
转换为
Int
,第二个
cast
a
转换回
Int

上面的代码非常难看,因为我们知道第二次强制转换不能失败,所以不需要第二次强制转换。我们可以使用
eqT
和类型相等GADT改进上述代码:

f :: forall a. Typeable a => a -> a
f x = case eqT :: Maybe (a :~: Int) of
   Nothing   -> x
   Just Refl -> x+1
基本上,
eqT
告诉我们两种(
Typeable
)类型是否相等。更好的是,在与
Just Refl
匹配后,编译器还知道它们是相等的,并允许我们使用
Int
值而不是
a
值,可以互换,并且不使用强制转换

事实上,多亏了GADT、
:~:
eqT
,现在大部分的
cast
的使用都已经过时了 过时的<代码>强制转换本身可以通过
eqT
轻松实现:

cast :: forall a. (Typeable a, Typeable b) => a -> Maybe b
cast x = case eqT :: Maybe (a :~: b) of
   Nothing   -> Nothing
   Just Refl -> Just x
结论:在哈斯克尔,我们得到了两个世界的最好。对于多态类型,我们确实有参数保证(自由定理)。我们还可以打破这些参数保证,使用“特殊”多态性,代价是额外的
可键入的
约束。

您可能感兴趣。它早于
Data.concure.concure
,因此今天有些事情可能会有所不同。
cast :: forall a. (Typeable a, Typeable b) => a -> Maybe b
cast x = case eqT :: Maybe (a :~: b) of
   Nothing   -> Nothing
   Just Refl -> Just x