Haskell TypeClass的调度是否动态? [英] Is the dispatch of a Haskell TypeClass dynamic?

查看:128
本文介绍了Haskell TypeClass的调度是否动态?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

鉴于以下Haskell代码快照:

  class Foo a where 
bar :: a - > ...
quux :: a - > ...
...

在运行时确定a的值 - 类调度此值。



我假设编译器可以在编译时静态检查类型,并确保没有无效的类型可以在其上发送。



现在,如果我们将其与Java中的动态调度进行比较:

  interface Flippable {
Flippable flip();
}

class Left implements Flippable {
Right flip();
}

class Right实现可折叠{
Left flip();
}

class Demo {
public static void main(String args []){
Flippable flippable = new Right();
System.out.println(flippable.flip);
}
}

假设: p>


  • Haskell可以在返回类型和多个参数上进行调度,使派遣与其他语言不同。



我的问题是: Haskell TypeClass的调度是否动态?

解决方案

这取决于动态调度的含义。在haskell中没有子类型,所以你的Java示例很难翻译。



在有类型类的情况下,说显示并希望将不同的元素放在列表中,您可以使用存在量化:

  { - #LANGUAGE ExistentialQuantification # - } 

data Showable = forall a。显示=>显示一个

实例Show Showable where
show(Showable x)= show x

test :: main()
test = let list = [ Showable True,Showablestring]
在打印列表中

- >>>>测试
- [True,string]

这里可以说发送发生动态。它发生在与C ++或Java中相同的方式。 显示字典带有一个对象,如C ++中的一个 vtable (或Java中的类定义ptr,dunno如何调用) p>

然而,正如 @MathematicalOrchid 所述,这是一种反模式。






但是,如果要从左侧翻转到右侧并返回,可以在类型定义中声明。

  { - #LANGUAGE ExistentialQuantification# - } 
{ - #LANGUAGE FunctionalDependencies# - }

class Flippable ab | a - > b其中
flip':: Flippable b a => a - > b

newtype INL = INL Int派生显示
newtype INR = INR Int派生显示

实例Flippable INL INR其中
flip'(INL x) = INR x

实例Flippable INR INL其中
flip'(INR x)= INL x

- >>>>翻转'$ INL 1
- INR 1
- >>>>翻转'$ flip'$ INL 1
- INL 1

在这种情况下 flip'调用已在编译时解决。






你可以有类Flip a where flip':: a - >可以使用存在量化也可以使用。那么连续调用将被动态调度。一如往常,这取决于你的需要。

  { - #LANGUAGE ExistentialQuantification# - } 
{ - #LANGUAGE FunctionalDependencies # - }
{ - #LANGUAGE StandaloneDeriving# - }

class Flip a where
flip':: a - > Flippable

- 显示仅用于复制目的
data Flippable = forall a。 (翻转a,显示a)=> Flippable a

派生实例Show Flippable

instance Flip Flippable where
flip'(Flippable x)= flip'x

newtype INL = INL Int导出显示
newtype INR = INR Int派生显示

实例Flip INL其中
flip'(INL x)=可翻转(INR x)

instance Flip INR where
flip'(INR x)= Flippable(INL x)

- >>>>翻转'$ flip'$ flip'$ INL 1
- Flippable(INR 1)






希望这回答你的问题。


Given the following Haskell code snapshot:

class Foo a where
   bar  :: a -> ...
   quux :: a -> ...
   ...

Where the value of a is determined at runtime - the class dispatches on this value.

I'm assuming that the compiler can statically check the types at compile-time, and ensure that no invalid types can dispatch on it.

Now if we compare this to a dynamic dispatch in Java:

interface Flippable {
  Flippable flip();
}

class Left implements Flippable {
  Right flip();
}

class Right implements Flippable {
  Left flip();
}

class Demo {
  public static void main(String args[]) {
    Flippable flippable = new Right();
    System.out.println(flippable.flip);
  }
}

Assumptions:

  • Haskell can dispatch on return type as well as multiple arguments making dispatch different to other languages.

My question is: Is the dispatch of a Haskell TypeClass dynamic?

解决方案

It depends what you mean by "dynamic" dispatch. There aren't subtyping in haskell, so your Java example is hard to translate.

In situation when you have type class, say Show and want to put different elements into the list, you can use existential quantification:

{-# LANGUAGE ExistentialQuantification #-}

data Showable = forall a. Show a => Showable a

instance Show Showable where
  show (Showable x) = show x

test :: main ()
test = let list = [Showable True, Showable "string"]
       in print list

-- >>> test
-- [True,"string"]

Here you can say that dispatch happens "dynamically". It happens in the same way as in C++ or Java. The Show dictionary is carried with an object, like a vtable in C++ (or class definition ptr in Java, dunno how it's called).

Yet, as @MathematicalOrchid explained, this is an anti-pattern.


Yet if you want to flip from Left to Right and back, you can state that in type class definition.

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FunctionalDependencies #-}

class Flippable a b | a -> b where
  flip' :: Flippable b a => a -> b

newtype INL = INL Int deriving Show
newtype INR = INR Int deriving Show

instance Flippable INL INR where
  flip' (INL x) = INR x

instance Flippable INR INL where
  flip' (INR x) = INL x

-- >>> flip' $ INL 1
-- INR 1
-- >>> flip' $ flip' $ INL 1
-- INL 1

In this case flip' calls are resolved already at compile-time.


You could have have class Flip a where flip' :: a -> Flippable using existential quantification too. Then consecutive calls will be dispatched dynamically. As always, it depends on your needs.

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE StandaloneDeriving #-}

class Flip a where
  flip' :: a -> Flippable

-- Show is only for repl purposes
data Flippable = forall a. (Flip a, Show a) => Flippable a

deriving instance Show Flippable

instance Flip Flippable where
  flip' (Flippable x) = flip' x

newtype INL = INL Int deriving Show
newtype INR = INR Int deriving Show

instance Flip INL where
  flip' (INL x) = Flippable (INR x)

instance Flip INR where
  flip' (INR x) = Flippable (INL x)

-- >>> flip' $ flip' $ flip' $ INL 1
-- Flippable (INR 1)


Hopefully this answers your question.

这篇关于Haskell TypeClass的调度是否动态?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆