Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 将类型附加到函数_Haskell_Functional Programming - Fatal编程技术网

Haskell 将类型附加到函数

Haskell 将类型附加到函数,haskell,functional-programming,Haskell,Functional Programming,我得到了一个自定义数据类型的示意图定义如下: data Foo = Foo { f1 :: Int , f2 :: b , f3 :: c } "(keyOf f1)=(f1 Foo), (keyOf f2)=(f2 Foo), (keyOf f3)=(f3 Foo)" data Foo b c = F1 Int | F2 b | F3 c 我需要做什么 将字符串附加到Foo中记录的每个函数。这在我的头脑中非常清楚,由于haskell多态性,它是微不足道的 第一次尝试:课

我得到了一个自定义数据类型的示意图定义如下:

data Foo = Foo
  { f1 :: Int
  , f2 :: b
  , f3 :: c
  }
"(keyOf f1)=(f1 Foo), (keyOf f2)=(f2 Foo), (keyOf f3)=(f3 Foo)"
data Foo b c = F1 Int | F2 b | F3 c
我需要做什么

将字符串附加到Foo中记录的每个函数。这在我的头脑中非常清楚,由于haskell多态性,它是微不足道的


第一次尝试:课堂

class Value a where
  val :: a -> String
class Query e where
  queries :: (Value a) => [(e -> a, String)]

instance Value Int where val = show
  instance Query Foo where
    queries =
      [ (f1, "function one")
      , (other records of Foo…)
      ]
这不管用。我不知道为什么。但我认为ghc需要一个类型为(Foo->a)的函数,但得到一个类型为(Foo->Int)的函数。 因此,多态性在这里不适用


第二次尝试:模式匹配

keyOf :: (Foo -> a) -> String
keyOf f1 = "function one"
keyOf f2 = "function two"
keyOf f3 = "function three"
keyOf _  = "unknown function"
看到它可以编译,我很满意。然后,在ghci中:

λ keyOf f2 = "function one"
显然,无法与函数名进行模式匹配


编辑:为什么我需要这样做

构造如下所示的查询字符串:

data Foo = Foo
  { f1 :: Int
  , f2 :: b
  , f3 :: c
  }
"(keyOf f1)=(f1 Foo), (keyOf f2)=(f2 Foo), (keyOf f3)=(f3 Foo)"
data Foo b c = F1 Int | F2 b | F3 c
更一般地说,折叠Foo中记录的每个函数及其关联的字符串,以及它的结果。例如:

exampleFoo :: Foo
exampleFoo = Foo "one" "two" "three"

assocs = [(f1, "function one"), (f2, "function two"), (f3, "function three")]

result == "function one=one, function two=two, function three=three"

现在,我真的想知道,如果不在haskell中使用元编程(比如TemplateHaskell),这种技巧是否可行。我没有考虑过什么选择吗?
谢谢。

我认为主要的问题是您混淆了
数据的工作原理

keyOf :: (Foo -> a) -> String
keyOf f1 = "function one"
keyOf f2 = "function two"
keyOf f3 = "function three"
keyOf _  = "unknown function"
我认为你的数据应该是这样的:

data Foo = Foo
  { f1 :: Int
  , f2 :: b
  , f3 :: c
  }
"(keyOf f1)=(f1 Foo), (keyOf f2)=(f2 Foo), (keyOf f3)=(f3 Foo)"
data Foo b c = F1 Int | F2 b | F3 c
这样,模式匹配将是:

keyOf :: Foo b c -> String
keyOf (F1 _) = "function one"
keyOf (F2 _) = "function two"
keyOf (F3 _) = "function three"

不需要“未知函数”
,因为我们正在对每个可能的Foo构造函数进行模式匹配。

我认为您在这里寻找的是一个存在的

如果你定义

data Selector e where
    Selector :: Value a => (e -> a) -> Selector e
(文件顶部需要
{-#LANGUAGE GADTs}

然后,您可以将类
查询定义为:

class Query e where
    queries :: [(Selector e, String)]

instance Query Foo where
    queries =
        [ (Selector f1, "function one")
        , (other records of Foo…)
        ]
您以前定义的问题是
查询的实现必须包含可以生成任何
类型的函数。您需要的是
查询的每个元素生成您选择的特定类型。这就是
选择器
类型所做的-它隐藏特定类型,以便您可以选择它,而不是
查询的调用者
可以选择

在这个特定的示例中,使用
选择器中的
a
类型所能做的唯一一件事就是将其转换为具有
值的
字符串,这样您就可以编写:

class Query e where
    queries :: [(e -> String, String)]

instance Query Foo where
    queries =
        [ (value . f1, "function one")
        , (other records of Foo…)
        ]

然而,如果
Value
是一个更复杂的类型类,尤其是一个通常有用的类型类,那么这种扁平化会变得非常冗长。

你能给出一个你想用每个函数所附字符串编写的程序的例子吗?是的,我编辑了这个问题。这足够清楚吗?恐怕不清楚-我不明白你关于查询字符串的意思。使用一些示例代码或伪代码可能会更清晰。我知道这有点困惑:我知道我的想法是错误的,但我想不出其他设计。我想我现在明白了-看我的答案。Foo数据类型由13条记录组成,我需要它们中的每一条来构造我的最终查询字符串,所以我认为sum类型与此无关。在这种情况下,模式匹配可能不是您需要的东西。这可能是问题的正确答案,但请不要在没有说明它们的情况下推荐存在主义(我实际上倾向于在好的用例中使用存在主义,但我相当怀疑这是一个)。这是一个好主意,但
[(选择器e,字符串)]
将生成实例查询Foo中的
[(选择器Foo,String)]
列表。然后,
Selector f1::Selector Int
将不适用于该上下文。有一个输入错误,它应该是
Selector::Value a=>(e->a)->Selector e
。但在这里你可能不需要存在主义。对于类型
选择器e
的值,您可以做的唯一一件事是将包含的函数应用于类型
e
的值,但是由于类型
a
是存在量化的,因此您可以对结果做的唯一一件事就是对其调用
val
,因为这是你所知道的关于
a
:它是
值的一个实例。由于
val
只是生成一个字符串,所以您最好只使用
数据选择器e=Selector(e->string)string
查询::[Selector]
。我同意这在这个特定的上下文中并不严格合适,但堆栈溢出会鼓励将问题简化为基本问题。对于更复杂的类型类,但基本问题相同,这将是完全合理的。