【问题标题】:How to define generic function without argument of generic type?如何定义没有泛型参数的泛型函数?
【发布时间】:2016-10-14 20:08:15
【问题描述】:

我现在正在阅读“Haskell Book”的幺半群部分,作者使用 QuickCheck 来检查幺半群定律。在自己写了一些东西之后,我有了这个代码:

module Main where

import Data.Monoid
import Test.QuickCheck

monoidAssoc :: (Eq m, Monoid m) => m -> m -> m -> Bool
monoidAssoc a b c = ((a <> b) <> c) == (a <> (b <> c))

monoidLeftId :: (Eq m, Monoid m) => m -> Bool
monoidLeftId a = (mempty <> a) == a

monoidRightId :: (Eq m, Monoid m) => m -> Bool
monoidRightId a = (a <> mempty) == a

type AssocCheck a = a -> a -> a -> Bool
type IdCheck a = a -> Bool

main :: IO ()
main = do
  quickCheck (monoidAssoc   :: AssocCheck (Maybe String))
  quickCheck (monoidLeftId  :: IdCheck (Maybe String))
  quickCheck (monoidRightId :: IdCheck (Maybe String))

  quickCheck (monoidAssoc   :: AssocCheck [String])
  quickCheck (monoidLeftId  :: IdCheck [String])
  quickCheck (monoidRightId :: IdCheck [String])

如您所见,main 函数有两个几乎相同的块,我想将其简化为这样的:

checkMonoid :: (Eq m, Monoid m) => m -> IO ()
checkMonoid = do
  quickCheck (monoidAssoc   :: AssocCheck m)
  quickCheck (monoidLeftId  :: IdCheck m)
  quickCheck (monoidRightId :: IdCheck m)


main :: IO ()
main = do
  checkMonoid :: Maybe String -> IO ()
  checkMonoid :: [String] -> IO ()

但这显然行不通。我在这里想要以某种方式将类型传递给checkMonoid 函数,以便quickCheck 函数知道必须生成什么arbitrary 数据。

【问题讨论】:

    标签: haskell generics


    【解决方案1】:

    这正是TypeApplication 让你做的事情——你可以显式地传递m 的类型。然后您还需要ScopedTypeVariables 以确保您内部的所有ms checkMonoid 都是相同的,并且AllowAmbiguousTypes 让GHC 知道您可以接受checkMonoid 在没有键入应用程序。

    {-# LANGUAGE TypeApplications, AllowAmbiguousTypes, ScopedTypeVariables #-}
    
    -- ...
    
    checkMonoid :: forall m. (Eq m, Monoid m, Show m, Arbitrary m) => IO ()
    checkMonoid = do
      quickCheck (monoidAssoc   :: AssocCheck m)
      quickCheck (monoidLeftId  :: IdCheck m)
      quickCheck (monoidRightId :: IdCheck m)
    
    
    main :: IO ()
    main = do
      checkMonoid @(Maybe String)
      checkMonoid @[String]
    

    TypeApplications 背后的原理是,Haskell 正在将多态函数转换为也将类型作为参数的函数 (see more here) - 通常 GHC 会负责确定要填充的类型参数。使用 @ 987654331@, @SomeType 表示“让前面函数调用的第一个类型参数为SomeType”。

    通过拥有forall m.,我确保 GHC 会执行上述操作。然后,当我调用checkMonoid 时,我会明确传递m 的类型。

    【讨论】:

      猜你喜欢
      • 2020-10-26
      • 1970-01-01
      • 2022-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多