有沒有一種使用型別資訊來選擇做不同事情的好方法?
例如,這不是有效的 Haskell,但我不明白為什么不能:
tostring :: (Show b) => b -> String
tostring x = f x where f = if b == String then tail . init . show else show
重要的部分不是得到正確的字串,而是使用型別b作為在功能/功能之間切換的一種方式。
uj5u.com熱心網友回復:
@chi 的回答已經演示了如何使用Typeable運行時型別檢查,但我想向我指出,這看起來正是型別類的用途。對于您的示例,唯一的問題是您不喜歡 的Show實作String:在這種情況下,只需創建自己的型別類!
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
-- The class
class MyShow a where
myShow :: a -> String
-- The instance for String
-- (The `OVERLAPPING` pragma is required, because
-- otherwise GHC won't know which instance to choose for String)
instance {-# OVERLAPPING #-} MyShow [Char] where
myShow = tail . init . show
-- For everything that is not a String, just copy the Show instance
instance Show a => MyShow a where
myShow = show
編輯:正如 leftaroundabout 所指出的,重疊實體很復雜,可能導致一些意外行為。查看檔案底部的示例。
uj5u.com熱心網友回復:
我將按原樣回答問題。Haskell 在編譯期間擦除所有型別資訊,主要是出于效率原因。默認情況下,當呼叫多型函式時,例如f :: a->a,沒有可用的型別資訊,并且f無法知道a實際是什么——在這種情況下,f只能是標識函式,無法終止或引發錯誤。
對于需要型別資訊的極少數情況,有Typeable. 具有 type 的多型函式f :: Typeable a => ...被傳遞給 type 的運行時描述a,允許它對其進行測驗。本質上,Typeable a約束迫使 Haskell 將運行時資訊保留到運行時。請注意,此型別別資訊必須在呼叫站點知道——要么是因為f使用完全已知的型別呼叫,要么是因為f使用部分已知的型別(比如f xwith x :: Maybe b)呼叫,但在范圍內有適當的Typeable限制(Typeable b在前面的示例中) )。
無論如何,這是一個例子:
{-# LANGUAGE TypeApplications, ScopedTypeVariables, GADTs #-}
import Data.Typeable
tostring :: forall b. (Show b, Typeable b) => b -> String
tostring x = case eqT @b @String of -- if b==String
Just Refl -> x -- then
Nothing -> show x -- else
請注意我們如何能夠x在“then”分支中回傳,因為已知它是一個String.
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/440292.html
