Haskell 从B或其他有用的东西

Haskell 从B或其他有用的东西,haskell,Haskell,我有: 我想编写函数::ca=>a,它将创建dsomestring。我将调用anyC并获取a,即AnyD。下一步是从AnyD创建dsomestring。在大多数现代语言中,这很容易。对于Haskell,我在Constrb中找到并看到了。所以,这个目标似乎是可行的,但是。。我遇到了一个问题,这篇文章看起来是错误的:我不能以Chris的方式构造任何东西,因为构造函数参数必须是代数类型,并且类似于fromcontr(toConstr(1::Int))的代码返回错误异常:Data.Data.constr

我有:


我想编写函数
::ca=>a
,它将创建
dsomestring
。我将调用
anyC
并获取
a
,即
AnyD
。下一步是从
AnyD
创建
dsomestring
。在大多数现代语言中,这很容易。对于Haskell,我在Constrb中找到并看到了
。所以,这个目标似乎是可行的,但是。。我遇到了一个问题,这篇文章看起来是错误的:我不能以Chris的方式构造任何东西,因为构造函数参数必须是代数类型,并且类似于
fromcontr(toConstr(1::Int))
的代码返回错误
异常:Data.Data.constrIndex不支持Prelude.Int,因为它不是代数数据类型。
。这同样适用于
String
,因此我无法将我的
someString
传递给我的构造函数!如何解决这个问题

具有类型的定义

class C a where
  anyC :: a 
data D = D String|AnyD deriving (Eq, Show, Data)
instance C D where
  anyC = AnyD
承诺提供任何类型的值
a
,只要它在类
C
内。
foo
的用户可以选择
a
foo
本身无法选择特定类型

使用您的设置,唯一可能的(非错误)定义是

foo :: C a => a
如果要返回
D“hello”
,则这是
D
类型。如果需要,可以使用该类型:

foo = anyC
还请注意,如果需要,还可以更改实例:

bar :: D
bar = D "hello"

关于

在大多数现代语言中,这很容易

事实并非如此。例如,在Java中,一个模糊的等价物可以是

//类型类,大致如下
接口C{
A anyC();
}
类D实现C{…}
阿福(){
返回新的D(…);
}
Java也不会接受这一点。除了其他问题,
foo()
承诺返回调用者选择的任何
A
,但它不能选择返回
D

Haskell类型变量大致对应于Java的泛型类型参数。您可能会转而考虑子类型,它存在于Java和其他OOP语言中,但Haskell没有使用


如果您想要一个来自constrb的
示例,您可以尝试以下方法:

instance C D where
  anyC = D "hello"
foo
计算结果为
D“新字符串”
。这可以通过嵌套
case eqT
s进行扩展,以便
field
覆盖更多类型(如果构造函数需要更多类型),以便我们检查所有需要的类型

还要注意,fromConstrB的
是有限的,因为如果我们的构造函数有两个相同类型的字段,我们就不能用不同的值填充字段。为此,我认为,我们需要从constrm
中求助于更复杂的


这里有一个小的方便助手函数。它接受一个
Constr
,以及一个“非类型化”参数列表(
Dynamic
在运行时进行所有类型检查),并尝试构建一个将构造函数应用于给定参数的值

{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables, TypeOperators, GADTs #-}

module FromConstr where

import Data.Data

data D = D String | AnyD deriving (Show, Data)

foo :: D
foo = fromConstrB field ctor
   where
   ctor :: Constr
   ctor = toConstr (D "aaa")
   field :: forall a. Data a => a
   field = case eqT :: Maybe (a :~: String) of
      Just Refl -> "new string"
      Nothing   -> error "trying to fill a non-string field"

如果构造函数有更多参数,则只需将列表变长,如
[toDyn“string”、toDyn(42::Int)、toDyn True]
中所示。
toDyn
函数将类型化值转换为“非类型化”值,以便它们可以一起存储在同一列表中,并传递给
applyConstr
。稍后,
applyConstr
将(在运行时)测试此列表的长度是否准确,是否具有正确类型的值。

具有类型的定义

class C a where
  anyC :: a 
data D = D String|AnyD deriving (Eq, Show, Data)
instance C D where
  anyC = AnyD
承诺提供任何类型的值
a
,只要它在类
C
内。
foo
的用户可以选择
a
foo
本身无法选择特定类型

使用您的设置,唯一可能的(非错误)定义是

foo :: C a => a
如果要返回
D“hello”
,则这是
D
类型。如果需要,可以使用该类型:

foo = anyC
还请注意,如果需要,还可以更改实例:

bar :: D
bar = D "hello"

关于

在大多数现代语言中,这很容易

事实并非如此。例如,在Java中,一个模糊的等价物可以是

//类型类,大致如下
接口C{
A anyC();
}
类D实现C{…}
阿福(){
返回新的D(…);
}
Java也不会接受这一点。除了其他问题,
foo()
承诺返回调用者选择的任何
A
,但它不能选择返回
D

Haskell类型变量大致对应于Java的泛型类型参数。您可能会转而考虑子类型,它存在于Java和其他OOP语言中,但Haskell没有使用


如果您想要一个来自constrb的
示例,您可以尝试以下方法:

instance C D where
  anyC = D "hello"
foo
计算结果为
D“新字符串”
。这可以通过嵌套
case eqT
s进行扩展,以便
field
覆盖更多类型(如果构造函数需要更多类型),以便我们检查所有需要的类型

还要注意,fromConstrB的
是有限的,因为如果我们的构造函数有两个相同类型的字段,我们就不能用不同的值填充字段。为此,我认为,我们需要从constrm
中求助于更复杂的


这里有一个小的方便助手函数。它接受一个
Constr
,以及一个“非类型化”参数列表(
Dynamic
在运行时进行所有类型检查),并尝试构建一个将构造函数应用于给定参数的值

{-# LANGUAGE DeriveDataTypeable, ScopedTypeVariables, TypeOperators, GADTs #-}

module FromConstr where

import Data.Data

data D = D String | AnyD deriving (Show, Data)

foo :: D
foo = fromConstrB field ctor
   where
   ctor :: Constr
   ctor = toConstr (D "aaa")
   field :: forall a. Data a => a
   field = case eqT :: Maybe (a :~: String) of
      Just Refl -> "new string"
      Nothing   -> error "trying to fill a non-string field"

如果构造函数有更多参数,则只需将列表变长,如
[toDyn“string”、toDyn(42::Int)、toDyn True]
中所示。
toDyn
函数将类型化值转换为“非类型化”值,以便它们可以一起存储在同一列表中,并传递给
applyConstr
。稍后,
applyConstr
将(在运行时)测试此列表的长度是否准确,是否具有正确类型的值。

我的问题是如何使用简单(内置)类型调用
fromConstrB
,而不是类型类