【发布时间】:2020-05-31 10:10:38
【问题描述】:
在 Haskell 中研究多变量函数时,我偶然发现了以下 SO 问题:
How to create a polyvariadic haskell function?
Haskell, polyvariadic function and type inference
我想我会通过实现一个函数来尝试一下,该函数接受可变数量的字符串并将它们连接/合并成一个字符串:
{-# LANGUAGE FlexibleInstances #-}
class MergeStrings r where
merge :: String -> r
instance MergeStrings String where
merge = id
instance (MergeStrings r) => MergeStrings (String -> r) where
merge acc = merge . (acc ++)
到目前为止,如果我使用至少一个字符串参数调用合并并且提供最终类型,则此方法有效。
foo :: String
foo = merge "a" "b" "c"
省略最终类型会导致错误,即编译以下内容
bar = merge "a" "b" "c"
结果
test.hs:12:7: error:
• Ambiguous type variable ‘t0’ arising from a use of ‘merge’
prevents the constraint ‘(MergeStrings t0)’ from being solved.
Relevant bindings include bar :: t0 (bound at test.hs:12:1)
Probable fix: use a type annotation to specify what ‘t0’ should be.
These potential instances exist:
instance MergeStrings r => MergeStrings (String -> r)
-- Defined at test.hs:6:10
instance MergeStrings String -- Defined at test.hs:4:10
• In the expression: merge "a" "b" "c"
In an equation for ‘bar’: bar = merge "a" "b" "c"
|
12 | bar = merge "a" "b" "c"
|
错误信息非常有意义,因为我可以很容易地想出例如
bar :: String -> String
bar = merge "a" "b" "c"
baz = bar "d"
不是将bar 渲染成单个字符串,而是渲染成一个接受并返回一个字符串的函数。
有没有办法告诉 Haskell 结果类型必须是 String 类型?例如,Text.Printf.printf "hello world" 在没有明确定义的情况下计算为 String。
【问题讨论】:
-
澄清一下:您似乎是在说,当
merge a b c etc…的类型无法推断时,您希望GHC推断String的类型,否则使用推断的类型。这种解释正确吗?我想不出任何办法来做到这一点,但我也不能肯定地说这是不可能的。 -
顺便说一句:看起来您的
printf示例仅有效,因为PrintfType具有IO的实例;在 GHCi 中进行测试时,任何可以专门用于IO的类型都将自动运行。如果我定义instance (a ~ ()) => MergeStrings (IO a) where merge = putStrLn,bar = merge "a" "b" "c"在 GHCi 中也适用于我。而且,在 GHCi 之外,printf "hello world"会导致模棱两可的类型变量错误,与bar = merge "a" "b" "c"完全相同。 -
为了澄清:我不希望 GHC 推断结果类型,而是在合并的定义端定义结果类型,这样在使用合并时我不必提供结果类型。你对 GHCi 和 IO 的观察真的很有趣,我也会和他们一起玩!似乎@max-taldykin 搞定了
标签: haskell polyvariadic