gpt4 book ai didi

haskell - 有选择地包装类实例的正确方法(或 "lift"函数,如 `sortBy` 、 `minimumBy` ……自动)

转载 作者:行者123 更新时间:2023-12-03 13:50:24 27 4
gpt4 key购买 nike

让一些类型实例化到许多类。有选择地替换某些实例的行为的正确方法是什么?

表达它的一种方法可以是构造 by运算符然后

data Person ...

sort personList -- default Ord instance
(sort `by` age) personList -- `age` modify `Ord` instance

在这里, sort可以是具有任何元数(例如 minimum )的任何函数(例如 insert )。

如果我们有一个像
reportPersons :: [Person] -> Report

它的功能使用 Ord (对列表进行排序), Show (格式化记录),...或其他特定实例;使用 funcBy我们必须写的模式
reportPersonsBy :: (Person -> Person -> Ordering) -> (Person -> String) -> ... -> [Person] -> Report

但我们可以使用 by用原始 reportPersons 包装每个行为 没有重构reportPersonsBy (解释的例子,最后没有解决相关问题)。

我的玩具(并不完全令人满意)解决方案是(最后是完整的代码):

将类型包装成类型以覆盖实例的类
class Wrappable m where
wrap :: forall a . a -> m a
unwrap :: forall a . m a -> a

by包装函数的函数
-- wrap functions: f a -> g a
by :: (Functor f, Functor g, Wrappable m) => (f (m a) -> g (m a)) -> m a -> f a -> g a
by f _ = fmap unwrap . f . fmap wrap

-- wrap functions: a -> f a -> g a
by_ f m a = f (wrap a) `by` m

现在我们可以写(在底部完整的例子)
-- f a -> f a
mapM_ print $ sort personList
mapM_ print $ (sort `by` age) personList

-- f a -> g a
print $ minimum personList
print $ (minimum `by` age) personList

-- a -> f a -> f a
print $ insert jane personList
print $ (insert `by_` age) jane personList

好的, by , by_ , ... 有效,但是 是什么?正确方法 ?如何写完整的多态 by ?

我试过但没有用
class Wrappable m => By m x f i o where
by :: f m x -> m x -> i m x -> o m x

能够将函数实例写为
instance (Wrappable m, Functor f, Functor g) => By m a (f (m a) -> g (m a)) (f a) (g a) where
by :: (f (m a) -> g (m a)) -> m a -> f a -> g a
by f _ = fmap unwrap . f . fmap wrap

谢谢!

报告示例

假设存在一个针对人员的报告功能( 可包装人员 )
reportPersons :: (Wrappable m, Show (m Person), Ord (m Person)) => [m Person] -> Maybe String
reportPersons = Just . unlines . map show . sort

带有每个实例的携带行为( OrdShow )。

让(不是多态的 by :()
by' :: (Functor f, Functor g, Wrappable m) => (f (m a) -> g b) -> m a -> f a -> g b
by' f _ = f . fmap wrap

和一个新的 Wrappable Person 的实例秒
newtype Format1 a = Format1 a deriving (Eq, Ord)
instance Show (Format1 Person) where show (Format1 (Person n a)) = "Name := " ++ n ++ " (" ++ show a ++ " years old)"
format1 :: Format1 Person; format1 = undefined
instance Wrappable Format1 where wrap = Format1
unwrap (Format1 p) = p

现在,我们可以选择性地报告重叠行为的人
putStrLn $ fromJust $ (reportPersons `by'` age)     personList
putStrLn $ fromJust $ (reportPersons `by'` format1) personList

带输出
ByAge (Person {personName = "John", personAge = 16})
ByAge (Person {personName = "Anne", personAge = 24})
ByAge (Person {personName = "Zorn", personAge = 37})
ByAge (Person {personName = "Peter", personAge = 42})

Name := Anne (24 years old)
Name := John (16 years old)
Name := Peter (42 years old)
Name := Zorn (37 years old)

使用 TypeFamilies或其他功能,我们可以链接 Wrappables ,等等...(这是一个玩具!!!我不知道怎么做的好)

(完整的沙箱代码)
{-# LANGUAGE RankNTypes, FlexibleInstances #-}
import Data.Maybe
import Prelude hiding (minimum)
import Data.List hiding (minimum)
import System.Random

{- safe minimum -}
minimum [] = Nothing; minimum xs = listToMaybe $ sort xs

data Person = Person { personName :: String, personAge :: Int } deriving (Eq, Show, Ord)

personList = [Person "Anne" 24, Person "John" 16, Person "Peter" 42, Person "Zorn" 37]
jane = Person "Jane" 26


class Wrappable m where
wrap :: forall a . a -> m a
unwrap :: forall a . m a -> a

-- wrap functions: f a -> g a
by :: (Functor f, Functor g, Wrappable m) => (f (m a) -> g (m a)) -> m a -> f a -> g a
by f _ = fmap unwrap . f . fmap wrap

-- wrap functions: a -> f a -> g a
by_ f m a = f (wrap a) `by` m

newtype ByAge a = ByAge a deriving (Eq, Show)
instance Ord (ByAge Person) where (ByAge (Person _ a)) `compare` (ByAge (Person _ b)) = a `compare` b
age :: ByAge Person; age = undefined
instance Wrappable ByAge where wrap = ByAge
unwrap (ByAge p) = p

main = do

-- f a -> f a
mapM_ print $ sort personList
mapM_ print $ (sort `by` age) personList

-- f a -> g a
print $ minimum personList
print $ (minimum `by` age) personList

-- a -> f a -> f a
print $ insert jane personList
print $ (insert `by_` age) jane personList

最佳答案

Let some type instanced to many classes. What is the proper way to replace, selectively, certain instances's behaviors?



正确的方法是使用普通的旧函数并使用 sortBy , maximumBy , groupBy等等。

我认为这是对类型类的滥用。保持简单,愚蠢!是的,这是基于意见的,让 stackoverflow 的投票系统对其进行排序(按)。

关于haskell - 有选择地包装类实例的正确方法(或 "lift"函数,如 `sortBy` 、 `minimumBy` ……自动),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27564159/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com