首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >声明实例的类型推断

声明实例的类型推断
EN

Stack Overflow用户
提问于 2013-08-13 18:31:20
回答 1查看 144关注 0票数 1

我想出了一个很好的练习,但做不到。

我们的想法是尝试用这样的方式来表达罗马数字,这样类型检查器就可以告诉我数字是否有效。

代码语言:javascript
复制
    {-# LANGUAGE RankNTypes
               , MultiParamTypeClasses #-}

    data One a b c = One a deriving (Show, Eq)
    data Two a b c = Two (One a b c) (One a b c) deriving (Show, Eq)
    data Three a b c = Three (One a b c) (Two a b c) deriving (Show, Eq)
    data Four a b c = Four (One a b c) (Five a b c) deriving (Show, Eq)
    data Five a b c = Five b deriving (Show, Eq)
    data Six a b c = Six (Five a b c) (One a b c) deriving (Show, Eq)
    data Seven a b c = Seven (Five a b c) (Two a b c) deriving (Show, Eq)
    data Eight a b c = Eight (Five a b c) (Three a b c) deriving (Show, Eq)
    data Nine a b c d e = Nine (One a b c) (One c d e) deriving (Show, Eq)

    data Z = Z deriving (Show, Eq) -- dummy for the last level
    data I = I deriving (Show, Eq)
    data V = V deriving (Show, Eq)
    data X = X deriving (Show, Eq)
    data L = L deriving (Show, Eq)
    data C = C deriving (Show, Eq)
    data D = D deriving (Show, Eq)
    data M = M deriving (Show, Eq)

    i :: One I V X
    i = One I

    v :: Five I V X
    v = Five V

    x :: One X L C
    x = One X

    l :: Five X L C
    l = Five L

    c :: One C D M
    c = One C

    d :: Five C D M
    d = Five D

    m :: One M Z Z
    m = One M

    infixr 4 #

    class RomanJoiner a b c where
      (#) :: a -> b -> c

    instance RomanJoiner (One a b c) (One a b c) (Two a b c) where
      (#) = Two

    instance RomanJoiner (One a b c) (Two a b c) (Three a b c) where
      (#) = Three

    instance RomanJoiner (One a b c) (Five a b c) (Four a b c) where
      (#) = Four

    instance RomanJoiner (Five a b c) (One a b c) (Six a b c) where
      (#) = Six

    instance RomanJoiner (Five a b c) (Two a b c) (Seven a b c) where
      (#) = Seven

    instance RomanJoiner (Five a b c) (Three a b c) (Eight a b c) where
      (#) = Eight

    instance RomanJoiner (One a b c) (One c d e) (Nine a b c d e) where
      (#) = Nine

    main = print $ v # i # i

这可能有不同的方法,而且解决方案是不完整的,但是现在我需要理解为什么它抱怨没有RomanJoiner (一个I V)(一个I V) b0的实例,而我认为我声明了这样一个合并器。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-08-13 19:43:00

问题是,选择实例并不是基于唯一有效的实例:一个扩展FunctionalDependencies有助于获得更多的类型推断。启用该功能,并使用| a b -> c表示可以从ab的类型推断出a # b的类型。不幸的是,这并不是您唯一需要做的事情,因为您将得到错误的Functional dependencies conflict between instance declarations。使用HList中定义的某些类(这些类可以在其他任何地方定义),冲突的两个实例可以组合成一个实例,其中两个实例(如果计算错误)将根据某些类型是否相等来选择可能的结果。

关于这个解决方案的一些评论是丑陋的:

  1. 如果您有更延迟的Show实例(如hCond),则不必再次在值级别复制类型级别上正在发生的事情(HCondinstance Show I where show _ = "I")。
  2. 使用更现代的扩展TypeFamilies,可以消除许多中间类型变量ba, bb, bc, babc ...。 {-# LANGUAGE RankNTypes,MultiParamTypeClasses,FunctionalDependencies,ScopedTypeVariables,UndecidableInstances,FlexibleContexts,FlexibleInstances #-} import Data.HList隐藏((#))导入Data.HList.TypeEqGeneric1导入Data.HList.TypeCastGeneric1 Unsafe.Coerce数据a a b c=1 a派生(Two,Eq)数据2 a b=2(A B c) (1 A B c)派生(Show,Eq)数据3 a c=3(A B c) (A B c) (2 A B C)派生(Show)Eq)数据4 a b c=4(1 A B c) (5 A B c)派生数据5 a c=5 b c=5 b b c=6 a b=6(5 A B c) (1 A B c)派生数据7 a b c=7(5 A B c) (2 A B c)派生(Show,Eq)数据8 a b=8(5 A B)(3 A B c)Eq)数据9 a b c d e=9(1 A B)(1 C D e)派生(Show,Eq)数据Z=Z派生(Show,Eq) --对最后一级数据I=i派生(Show,Eq)数据V=V派生(Show,Eq)数据X=X派生(Show,Eq)数据L=L派生(Show,Eq)数据C=C派生(Show,Eq)数据D=D派生(Show,Eq)数据M=M派生(Show,Eq)Eq) I ::1 I V i=1 I v ::5 I V v=5 V x ::1 X L c=1 X 1 1:5 X L C l=5 L c:1 C D M c=1 C d:5 C D M d=5 D m ::1 M Z Z m=1 M infixr 4# class RomanJoiner a c x a b -> c其中(#):a -> b -> c实例RomanJoiner (1 A B c)(2 A B c) (3 A B c)其中(#) =3实例RomanJoiner (1 A B c) (5 A B c) (4 A B c)其中(#) =4实例RomanJoiner (5 A B c) (1 A B c) (6 A B c)其中(#) =6实例RomanJoiner (5 A B c) (2 A B c) (7 A B c)其中(#) =7实例RomanJoiner (5 A B c)(3 A B c) (8 A B c)其中(#) =8数据错误=a bc a‘b’c‘ba的错误实例。(TypeEq a‘ba,TypeEq b’bb‘bb,TypeEq c c’bc,HAnd ba bab,HAnd babc,TypeEq c a‘bn,HCond bn (9 a bc b’c')错误9,HCond babc (2 A B) => RomanJoiner (1 A B)(1 a‘b’c') z,其中(#) x= hCond (未定义: babc) (2 (uc :1 a b c) (uc :1 a b c)) $ hCond (未定义:b‘b’)(hCond (uc :1 a b)c) (uc y ::一个c‘b’c‘)错误,其中uc = unsafeCoerce main = print $v#i#i {-使用ghc 762打印HList-0.2.3 *Main>主七(5 V) (2(1 I) (1 I) -}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18216545

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档