Scala与Haskell中List [T]和Set [T]上的模式匹配:类型擦除的效
Haskell相当于下面的代码会产生正确的答案吗?
可以修复此Scala代码以生成正确的答案吗?如果有,怎么样? object TypeErasurePatternMatchQuestion extends App { val li=List(1,2,3) val ls=List("1","2","3") val si=Set(1,3) val ss=Set("1","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是编译器对值o的所有知识.这就是为什么从那时起你只能依赖有关类型的运行时信息.
像case o:List [Int]这样的case表达式是使用JVM的特殊运行时机制实例解析的.但是,您遇到的错误行为是由此机制仅考虑第一级类型(List [Int]中的List)并忽略参数(List [Int]中的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","3"))) println(whatIsIt(Set("1","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,3] :: [Int]) putStrLn $whatIsIt $toDyn (["1","3"] :: [String]) putStrLn $whatIsIt $toDyn (Data.Set.fromList ["1","3"] :: Set String) 输出: [Int] [String] Set String 但是,我必须大胆地概述这远不是Haskell编程的典型场景.语言的类型系统足以解决极其复杂的问题,同时保持所有类型级别的信息(和安全性). Dynamic仅用于低级库中的特殊情况. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- scala – slick 3.0.0,未加载HikariCP驱动程序 – IllegalA
- macos – 如何使用CHMOD获取“drwx — r-x”文件夹权限? –
- 使用Bootstrap + Vue.js实现表格的动态展示、新增和删除功能
- 如何部署WebService到服务器上(adf commonJ)
- ORA-00704: bootstrap process failure 的处理
- gVim在右边显示每个带星号的文件(和粗体)?
- 在GNOME shell 3.10上搜索文件和草率鼠标焦点模式时,PhpSto
- shell变量------shift
- Angular 2中的ng-title指令发生了什么变化?
- bash – Bourne shell中的“2 <&1”重定向是什么?