gpt4 book ai didi

scala - Scala 与 Haskell 中 List[T] 和 Set[T] 上的模式匹配 : effects of type erasure

转载 作者:行者123 更新时间:2023-12-04 10:25:09 25 4
gpt4 key购买 nike

与下面代码等效的 Haskell 会产生正确的答案吗?

可以修复此 Scala 代码以产生正确的答案吗?如果是,如何?

object TypeErasurePatternMatchQuestion extends App {
val li=List(1,2,3)
val ls=List("1","2","3")
val si=Set(1,2,3)
val ss=Set("1","2","3")
def whatIsIt(o:Any)=o match{
case o:List[Int] => "List[Int]"
case o:List[String] => "List[String]"
case o:Set[Int] => "Set[Int]"
case o:Set[String] => "Set[String]"
}

println(whatIsIt(li))
println(whatIsIt(ls))
println(whatIsIt(si))
println(whatIsIt(ss))

}

打印:
List[Int]
List[Int]
Set[Int]
Set[Int]

但我希望它能够打印:
List[Int]
List[String]
Set[Int]
Set[String]

最佳答案

您必须通过说 o:Any 来理解这一点。您删除了有关类型的所有特定信息,并进一步删除了类型 Any是编译器所知道的关于值 o 的全部内容.这就是为什么从那时起您只能依赖有关类型的运行时信息。

大小写表达式如 case o:List[Int]使用 JVM 的特殊 instanceof 解决运行时机制。但是,您遇到的错误行为是由这种机制引起的,它只考虑了第一类类型(List 中的 List[Int] )并忽略了参数(Int 中的 List[Int] )。这就是为什么它对待List[Int]等于 List[String] .这个问题被称为“Generics Erasure”。

另一方面,Haskell 执行完整的类型删除,这在 answer by Ben 中有很好的解释。 .

所以这两种语言的问题是一样的:我们需要提供关于类型及其参数的运行时信息。

在 Scala 您可以使用“反射”库来实现,它隐式地解析该信息:

import reflect.runtime.{universe => ru}
def whatIsIt[T](o : T)(implicit t : ru.TypeTag[T]) =
if( t.tpe <:< ru.typeOf[List[Int]] )
"List[Int]"
else if ( t.tpe <:< ru.typeOf[List[String]] )
"List[String]"
else if ( t.tpe <:< ru.typeOf[Set[Int]] )
"Set[Int]"
else if ( t.tpe <:< ru.typeOf[Set[String]] )
"Set[String]"
else sys.error("Unexpected type")

println(whatIsIt(List("1","2","3")))
println(whatIsIt(Set("1","2","3")))

输出:
List[String]
Set[String]

haskell 对多态性有非常不同的方法。最重要的是,它没有子类型多态性(虽然它不是一个弱点),这就是为什么你的例子中的类型切换模式匹配是无关紧要的。但是,可以将上面的 Scala 解决方案非常紧密地翻译成 Haskell:
{-# LANGUAGE MultiWayIf, ScopedTypeVariables #-}
import Data.Dynamic
import Data.Set

whatIsIt :: Dynamic -> String
whatIsIt a =
if | Just (_ :: [Int]) <- fromDynamic a -> "[Int]"
| Just (_ :: [String]) <- fromDynamic a -> "[String]"
| Just (_ :: Set Int) <- fromDynamic a -> "Set Int"
| Just (_ :: Set String) <- fromDynamic a -> "Set String"
| otherwise -> error "Unexpected type"

main = do
putStrLn $ whatIsIt $ toDyn ([1, 2, 3] :: [Int])
putStrLn $ whatIsIt $ toDyn (["1", "2", "3"] :: [String])
putStrLn $ whatIsIt $ toDyn (Data.Set.fromList ["1", "2", "3"] :: Set String)

输出:
[Int]
[String]
Set String

但是我必须大胆地概述 这与 Haskell 编程的典型场景相去甚远 .该语言的类型系统足够强大,可以解决极其复杂的问题,同时保持所有类型级别的信息(和安全性)。 Dynamic仅在低级库中非常特殊的情况下使用。

关于scala - Scala 与 Haskell 中 List[T] 和 Set[T] 上的模式匹配 : effects of type erasure,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22388302/

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