[英]Composing functions with a intermediate polymorphic type in Haskell
我有以下文件:
module SimpleComposition where
class Intermediate a where
f :: a -> Int
g :: Char -> a
h :: Char -> Int
h = f . g
嘗試在 ghci 中加載它時,出現錯誤:
main.hs:8:5: error:
* No instance for (Intermediate a0) arising from a use of `f'
* In the first argument of `(.)', namely `f'
In the expression: f . g
In an equation for `h': h = f . g
|
8 | h = f . g
| ^
我認為問題在於有人可能會使用 2 種不同類型,它們是此組合中的Intermediate
實例。 當我導出這個模塊時,我如何保證它是一樣的?
PS:這是一個比我之前提出的問題更好的最小示例(如何在 Haskell 中組合多態函數? )。
問題不在於無法推斷出實例,而是編譯器確實無法知道您可能想要的類型。 g
可以產生任何向它詢問的類型(前提是它有一個Intermediate
實例), f
可以使用任何這樣的類型......但沒有人指定哪一個。
但這很容易解決:現在只需 select 一個類型。 當然,它必須是有實例的; 例如,如果你有
instance Intermediate Char where
f = fromEnum
g = id
那么你可以使用
h :: Char -> Int
h = (f :: Char -> Int) . g
修復類型選擇的更簡潔的方法是使用語法擴展:
{-# LANGUAGE TypeApplications #-}
h = f @Char . g
...或者,為了強調您只是在中間固定類型,
h = f . id @Char . g
我認為問題在於有人可能會使用 2 種不同類型,它們是此組合中的中間實例。
沒有問題是 Haskell 不能再從簽名派生什么a
要使用。 假設有兩種Intermediate
類型:
instance Intermediate Char where
# …
instance Intermediate Bool where
# …
現在h
有兩種實現:
h :: Char -> Int
h = f . (g :: Char -> Char)
或者:
h :: Char -> Int
h = f . (g :: Char -> Bool)
可以使用無數種Intermediate
類型。 問題是 Haskell 無法根據類型簽名判斷使用什么類型。
我們可以給它一個類型提示,但這當然意味着中間類型是固定的。
解決此問題的一種簡單方法是使用asTypeOf:: a -> a -> a
。 這基本上是一個const
function,但是兩個參數具有相同的類型。 因此,這用於添加提示要使用什么類型,例如:
h :: Intermediate a => a -> Char -> Int
h a x = f (g x `asTypeOf` a)
因此,此處參數a
值並不重要,這是一種“注入”類型的方法,該類型將用作g
的結果和f
的參數的類型。
如果您以后使用h
,您可以使用:
h (undefined :: Char) 'a'
指定f
應該具有類型Char -> Char
,並且g
應該具有類型Char -> Int
。
就像@leftroundabout和@DanielWagner說的那樣,不使用這種虛擬變量的更干凈的解決方案是在簽名中添加類型變量:
{-# LANGUAGE AllowAmbiguousTypes, ScopedTypeVariables, TypeApplications #-}
h :: forall a. Intermediate a => Char -> Int
h = f . g @ a
然后我們可以將h
與類型變量一起使用:
h @ Char 'a'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.