Real World Haskell - Chapter 6. Using Typeclasses

Haskell-找出有向图的所有最短路 利用Haskell语言找出有向图的所有最短路 立即下载

 

 

 

 

Chapter 6. Using Typeclasses

 

用class 声明Typeclass 就是声明一组函数。

 

The Need for Typeclasses

 

Color 相等测试(后面有改进版)

 

data Color = Red | Green | Blue

 

colorEq :: Color -> Color -> Bool

colorEq Red Red = True

colorEq Green Green = True

colorEq Blue Blue = True

colorEq _ _ = False

 

cc = colorEq Red Red  -- >True

dd = colorEq Red Green  -- >False

 

String 相等测试

 

stringEq :: [Char] -> [Char] -> Bool

 

stringEq [] [] = True

stringEq (x:xs) (y:ys) = x == y && stringEq xs ys

stringEq _ _ = False

 

现在你看到了,我们要写不同的函数来对不同的类型作相等测试,不仅效率低而且讨人厌。

 

如果可以用“==” 操作符来比较任何东西就会方便得多。


 

What Are Typeclasses?

 

Typeclasses 定义了一组函数,这些函数对于给定的不同类据类型有不同的实现。Typeclasses 可能看起来像OO 中的对象,但实际上它们相当不同。

 

让我们用Typeclasses 来解决前面的困境。作为开始,我们必须定义Typeclasses 本身。

 

我们需要一个函数,它不在乎其参数类型是什么。这是我们的第一个Typeclasses 定义:

 

class BasicEq a where

    isEqual :: a -> a -> Bool

 

这里我们声明了一个名为BasicEq 的typeclass,而a 是BasicEq 的实例。

 

class 是定义typeclass 的关键字。注意了,它和OO 的类没有任何关系。

 

实例化typeclass 的类型

 

instance BasicEq Bool where

    isEqual True True = True

    isEqual False False = True

    isEqual _ _ = False

 

定义不相等函数也可能是有用的

 

class BasicEq2 a where

    isEqual2 :: a -> a -> Bool

    isNotEqual2 :: a -> a -> Bool

   

这里两个函数的定义循环依赖,必须且只须定义其中一个

 

class BasicEq3 a where

    isEqual3 :: a -> a -> Bool

    isEqual3 x y = not (isNotEqual3 x y)

 

    isNotEqual3 :: a -> a -> Bool

    isNotEqual3 x y = not (isEqual3 x y)

 

如不给出定义,这两函数会引发无限循环。

 

 

内置typeclass Eq 的定义

{-

class Eq a where

    (==), (/=) :: a -> a -> Bool  -- 亮点,有相同签名的两函数可以一起定义

 

        -- Minimal complete definition:

        -- (==) or (/=)

    x /= y = not (x == y)

    x == y = not (x /= y)

-}

 

Declaring Typeclass Instances

 

Color 相等测试

 

instance BasicEq3 Color where

    isEqual3 Red Red = True

    isEqual3 Green Green = True

    isEqual3 Blue Blue = True

    isEqual3 _ _ = False

 

这里isNotEqual3 这里没有给出定义,所以编译器自动使用Typeclass 声明isNotEqual3 时的默入定义。


 

Important Built-in Typeclasses

 

Haskell 的Prelude 包定义了一些标准typeclass 。

 

typeclass 是Haskell 语言的重要核心。

 

Show

 

Show 是一个typeclass ,用于将values 转成Strings。

 

类型类Show 最重要的函数是show。

 

{-

ghci> :type show

show :: (Show a) => a -> String

 

ghci> show 1

"1"

ghci> show [1, 2, 3]

"[1,2,3]"

ghci> show (1, 2)

"(1,2)"

-}

 

{-

ghci> putStrLn (show 1)

1

ghci> putStrLn (show [1,2,3])

[1,2,3]

 

ghci> show "Hello!"

"/"Hello!/""

ghci> putStrLn (show "Hello!")

"Hello!"

ghci> show ['H', 'i']

"/"Hi/""

ghci> putStrLn (show "Hi")

"Hi"

ghci> show "Hi, /"Jane/""

"/"Hi, ///"Jane///"/""

ghci> putStrLn (show "Hi, /"Jane/"")

"Hi, /"Jane/""

-}

 

为自已的类型定义Show 实例

 

instance Show Color where

    show Red = "Red"

    show Green = "Green"

    show Blue = "Blue"

 

show Red  -- >"Red"


 

Read

 

Read 这个typeclass 与Show 本质上相反。它定义了一些函数,这些函数接受一个String,解析它,并返回任意类型的数据(就是你用来实例化的那个类型)。Read 最有用的函数是read。

 

{-

main = do

        putStrLn "Please enter a Double:"

        inpStr <- getLine  -- 读入一行

        let inpDouble = (read inpStr)::Double

        putStrLn ("Twice " ++ show inpDouble ++ " is " ++ show (inpDouble * 2))

-}

 

(read inpStr)::Double 类似于“显示类型转换”,因为read 的返回值是a ,read String => a 。

 

ghci 在内部使用show 来显示结果。

 

instance Read Color where

    readsPrec _ value =

        tryParse [("Red", Red), ("Green", Green), ("Blue", Blue)]

        where tryParse [] = []

              tryParse ((attempt, result):xs) =

                    if (take (length attempt) value) == attempt

                        then [(result, drop (length attempt) value)]

                        else tryParse xs

 

{-

ghci> (read "Red")::Color

Red

ghci> (read "Green")::Color

Green

ghci> (read "Blue")::Color

Blue

ghci> (read "[Red]")::[Color]

[Red]

ghci> (read "[Red,Red,Blue]")::[Color]

[Red,Red,Blue]

ghci> (read "[Red, Red, Blue]")::[Color]

*** Exception: Prelude.read: no parse

-}

 

Parsec 比Read 更易用,Read 通常只用于简单任务。(参见第16章)


 

Serialization with read and show

 

read 和show 是进行序列化的极好工具。show 生成人和机器都可读的输出。

 

String 处理通常是lazy 的,所以read 和show 可以用来处理相当大的数据结构。

 

先写文件,文件名是“test”,内容是“[Just 5,Nothing,Nothing,Just 8,Just 9]”

 

{-

ghci> let d1 = [Just 5, Nothing, Nothing, Just 8, Just 9]::[Maybe Int]

ghci> putStrLn (show d1)

[Just 5,Nothing,Nothing,Just 8,Just 9]

ghci> writeFile "test" (show d1)  -- 亮点,写文件的方法

-}

 

然后再读回来

 

{-

ghci> input <- readFile "test"

"[Just 5,Nothing,Nothing,Just 8,Just 9]"

ghci> let d2 = read input  -- 亮点,读文件的方法

<interactive>:1:9:

Ambiguous type variable `a' in the constraint:

`Read a' arising from a use of `read' at <interactive>:1:9-18

Probable fix: add a type signature that fixes these type variable(s)

ghci> let d2 = (read input)::[Maybe Int]

ghci> print d1

[Just 5,Nothing,Nothing,Just 8,Just 9]

ghci> print d2

[Just 5,Nothing,Nothing,Just 8,Just 9]

ghci> d1 == d2

True

-}

 

{-

ghci> putStrLn $ show [("hi", 1), ("there", 3)]  -- 亮点,用“$” 操作符当括号

[("hi",1),("there",3)]

ghci> putStrLn $ show [[1, 2, 3], [], [4, 0, 1], [], [503]]

[[1,2,3],[],[4,0,1],[],[503]]

ghci> putStrLn $ show [Left 5, Right "three", Left 0, Right "nine"]

[Left 5,Right "three",Left 0,Right "nine"]

ghci> putStrLn $ show [Left 0, Right [1, 2, 3], Left 5, Right []]

[Left 0,Right [1,2,3],Left 5,Right []]

-}

 

Numeric Types

 

Haskell 的数值类型非常强大。你可以使用从32 位到64 位的整数,还有任意精度的比例数。“+” 可以适用于所有这些数值。这是使用typeclass 实现的。你也可以定义自已的数值类型,并使它们成为Haskell 中的fist-class citizens。

 

Equality, Ordering, and Comparisons

 

“==” 和“/=” 定义于Eq class 。

 

“>=” 和“<=” 定义于Ord class 。

 

Ord 的任何实例都可以用Data.List.sort 排序。

 

几乎所有Haskell 的类型都是Eq 的实例,Ord 的实例也接近这么多。


 

Automatic Derivation

 

对一些简单的数据类型,Haskell 编译器可以自动为我们继承实例,包括Read, Show, Bounded, Enum, Eq, 和 Ord

 

使用deriving 关键字自动继承typeclass 实例

 

data Color = Red | Green | Blue

     deriving (Read, Show, Eq, Ord)

 

{-

ghci> show Red

"Red"

ghci> (read "Red")::Color

Red

ghci> (read "[Red,Red,Blue]")::[Color]

[Red,Red,Blue]

ghci> (read "[Red, Red, Blue]")::[Color]

[Red,Red,Blue]

ghci> Red == Red

True

ghci> Red == Blue

False

ghci> Data.List.sort [Blue,Green,Blue,Red]  -- 大小和定义顺序一致

[Red,Green,Blue,Blue]

ghci> Red < Blue

True

-}

    

注意到Color 的order 接照我们定义构造器的顺序来定义的。

 

类似这样的data MyType = MyType (Int -> Bool) 不能自动继承,因为show 不知道怎样render 一个函数。

 

data CannotShow = CannotShow

                deriving (Show)

 

-- 不能编译

data CannotDeriveShow = CannotDeriveShow CannotShow

                      deriving (Show)

 

-- 正确

data OK = OK

 

instance Show OK where

    show _ = "OK"

 

data ThisWorks = ThisWorks OK

               deriving (Show)


 

Typeclasses at Work: Making JSON Easier to Use

 

--import JSON

 

result :: JValue

 

result = JObject [

    ("query", JString "awkward squad haskell"),

    ("estimatedCount", JNumber 3920),

    ("moreResults", JBool True),

    ("results", JArray [

        JObject [

        ("title", JString "Simon Peyton Jones: papers"),

        ("snippet", JString "Tackling the awkward ..."),

        ("url", JString "http://.../marktoberdorf/")

        ]])

    ]

 

type JSONError = String

class JSON a where

    toJValue :: a -> JValue

    fromJValue :: JValue -> Either JSONError a  -- Either 类似于Mabe,我们用它表示这里的操作可能会失败。

 

instance JSON JValue where

    toJValue = id

    fromJValue = Right

 

More Helpful Errors

 

fromJValue 函数使用了Either 类型,和Mabe 一样,Either这个类型也是也是预定义了的。我们用它表示那里的操作可能会失败。

 

Either 的定义

{-

data Either a b = Left a

                | Right b

                deriving (Eq, Ord, Read, Show)

-}

 

 

Either 的结构类似于Nothing ,但是Either 有一个“something bad happened”的Left 构造器。

 

instance JSON Bool where

    toJValue = JBool

    fromJValue (JBool b) = Right b

    fromJValue _ = Left "not a JSON boolean"  -- 有不好的事情发生了!

 

Making an Instance with a Type Synonym

 

Haskell 98 标准不允许写这样的代码,虽然看起来很perfectly:

 

instance JSON String where

    toJValue = JString

    fromJValue (JString s) = Right s

    fromJValue _ = Left "not a JSON string"

 

 

使用这个可以使得上面的代码有效:

 

{-# LANGUAGE TypeSynonymInstances #-}  -- 把这个放到源码的最顶端(不是top 是不行的!)


 

Living in an Open World

 

-- JSONClass.hs

{-# LANGUAGE TypeSynonymInstances #-}

 

module JSONClass () where

 

import JSON

 

type JSONError = String

 

class JSON a where

    toJValue :: a -> JValue

    fromJValue :: JValue -> Either JSONError a

 

instance JSON JValue where

    toJValue = id

    fromJValue = Right

 

instance JSON Bool where

    toJValue = JBool

    fromJValue (JBool b) = Right b

    fromJValue _ = Left "not a JSON boolean"

 

instance JSON String where

    toJValue = JString

    fromJValue (JString s) = Right s

    fromJValue _ = Left "not a JSON string"

 

doubleToJValue :: (Double -> a) -> JValue -> Either JSONError a

doubleToJValue f (JNumber v) = Right (f v)

doubleToJValue _ _ = Left "not a JSON number"

 

instance JSON Int where

    toJValue = JNumber . realToFrac

    fromJValue = doubleToJValue round

 

instance JSON Integer where

    toJValue = JNumber . realToFrac

    fromJValue = doubleToJValue round

 

instance JSON Double where

    toJValue = JNumber

    fromJValue = doubleToJValue id

 

--------------------------------------------------------------

-- BrokenClass.hs

{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}

 

module BrokenClass () where

 

import JSON

 

type JSONError = String

 

class JSON a where

    toJValue :: a -> JValue

    fromJValue :: JValue -> Either JSONError a

 

instance (JSON a) => JSON [a] where

    toJValue = undefined

    fromJValue = undefined

 

instance (JSON a) => JSON [(String, a)] where

    toJValue = undefined

    fromJValue = undefined

 

aa = toJValue [("foo","bar")]  -- 出错!解释见后面。-- Error:“Overlapping instances for JSON [([Char], [Char])]”

 

When Do Overlapping Instances Cause Problems?

 

toJValue [("foo","bar")]  -- Error:“Overlapping instances for JSON [([Char], [Char])]”

 

要了解Overlapping Instances 错误是怎么回事看下面的代码:

 

-- 要正常编译加这个:{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}

class Borked a where

    bork :: a -> String

 

instance Borked Int where

    bork = show

 

instance Borked (Int, Int) where

    bork (a, b) = bork a ++ ", " ++ bork b

 

instance (Borked a, Borked b) => Borked (a, b) where

    bork (a, b) = ">>" ++ bork a ++ " " ++ bork b ++ "<<"

 

我们有两个pairs 实例:一个是Int pairs,另一个是任意Borked pairs。(不知道应该匹配哪一个?)

 

Relaxing Some Restrictions on Typeclasses

 

TypeSynonymInstances 扩展使得我们可以使用[a] 这种泛类型的特化版本[Char]

 

OverlappingInstances 扩展使得当发生多匹配时使得编译器选择最特殊的那一个。

 

通常联合使用TypeSynonymInstances,OverlappingInstances

 

{-

{-# LANGUAGE TypeSynonymInstances, OverlappingInstances #-}

import Data.List

class Foo a where

    foo :: a -> String

 

instance Foo a => Foo [a] where

    foo = concat . intersperse ", " . map foo

 

instance Foo Char where

    foo c = [c]

 

instance Foo String where

    foo = id

-}


 

How Does Show Work for Strings?

 

略

 

How to Give a Type a New Identity

 

除了data 关键字,Haskell 还提供了一个newtype 关键字用来定义新类型

 

data DataInt = D Int

             deriving (Eq, Ord, Show)

 

newtype NewtypeInt = N Int

                   deriving (Eq, Ord, Show)

 

newtype 声明的目的是重命名一个已存在的类型,给它一个不同的标识。注意到newtype 和data 声明是很像的。

 

使用newtype 声明的是一种真正的新类型,而用type 声明的只是一种昵称

 

newtype UniqueID = UniqueID Int

                 deriving (Eq)

 

UniqueID 和Int 是两种不同的类型,作为UniqueID 的用户我们不知道它是用Int 实现的。

 

{-

ghci> N 1 < N 2

True

-}

 

因为没有暴露Int 的Num 或Integral 实例,所以NewtypeInt 的值不是数字:

{-

ghci> N 313 + N 37  -- 出错

-}


 

Differences Between Data and Newtype Declarations

 

newtype 的使用比Date 有更多的限制。

 

newtype 只能有一个值构造器,构造器的参数也只能有一个。

 

{-

data TwoFields = TwoFields Int Int

 

-- ok: exactly one field

newtype Okay = ExactlyOne Int

 

-- ok: type parameters are no problem

newtype Param a b = Param (Either a b)

 

-- ok: record syntax is fine

newtype Record = Record {

     getInt :: Int

    }

 

-- bad: no fields

newtype TooFew = TooFew

 

-- bad: more than one field

newtype TooManyFields = Fields Int Int

 

-- bad: more than one constructor

newtype TooManyCtors = Bad Int

                     | Worse Int

-}

 

用data 创建类型在运行时有一个bookkeeping 开销,而newtype 没有。

 

下面的代码不会crash

 

{-

ghci> case undefined of N _ -> 1

1

-}

 

因为在运行时没有构造器要present 。匹配的时侯N _ 简单的等效于wild card “_” ,因为wild card 总是匹配的,所以就不需要去evaluated 那个undefined 。


 

JSON Typeclasses Without Overlapping Instances

 

-- JSONClass

{-# LANGUAGE TypeSynonymInstances #-}

 

module JSONClass ( JAry(fromJAry), jary ) where

 

--import JSON

 

import Control.Arrow (second)

 

data JValue = JString String

            | JNumber Double

            | JBool Bool

            | JNull

            | JObject (JObj JValue) -- was [(String, JValue)]

            | JArray (JAry JValue) -- was [JValue]

            deriving (Eq, Ord, Show)

 

 

type JSONError = String

 

class JSON a where

    toJValue :: a -> JValue

    fromJValue :: JValue -> Either JSONError a

 

instance JSON JValue where

    toJValue = id

    fromJValue = Right

 

instance JSON Bool where

    toJValue = JBool

    fromJValue (JBool b) = Right b

    fromJValue _ = Left "not a JSON boolean"

 

instance JSON String where

    toJValue = JString

    fromJValue (JString s) = Right s

    fromJValue _ = Left "not a JSON string"

 

doubleToJValue :: (Double -> a) -> JValue -> Either JSONError a

doubleToJValue f (JNumber v) = Right (f v)

doubleToJValue _ _ = Left "not a JSON number"

 

instance JSON Int where

    toJValue = JNumber . realToFrac

    fromJValue = doubleToJValue round

 

instance JSON Integer where

    toJValue = JNumber . realToFrac

    fromJValue = doubleToJValue round

 

instance JSON Double where

    toJValue = JNumber

    fromJValue = doubleToJValue id

 

 

newtype JAry a = JAry {

    fromJAry :: [a]

   } deriving (Eq, Ord, Show)

 

 

-- 通常导出一个newtype 时我们不导出它的构造器,而是提供一个函数来构造

jary :: [a] -> JAry a

jary = JAry

 

newtype JObj a = JObj {

    fromJObj :: [(String, a)]

   } deriving (Eq, Ord, Show)

 

jaryFromJValue :: (JSON a) => JValue -> Either JSONError (JAry a)

jaryToJValue :: (JSON a) => JAry a -> JValue

 

instance (JSON a) => JSON (JAry a) where

    toJValue = jaryToJValue

    fromJValue = jaryFromJValue

 

 

listToJValues :: (JSON a) => [a] -> [JValue]

listToJValues = map toJValue

 

 

jvaluesToJAry :: [JValue] -> JAry JValue

jvaluesToJAry = JAry

 

jaryOfJValuesToJValue :: JAry JValue -> JValue

jaryOfJValuesToJValue = JArray

 

jaryToJValue = JArray . JAry . map toJValue . fromJAry

 

jaryFromJValue (JArray (JAry a)) =

    whenRight JAry (mapEithers fromJValue a)

jaryFromJValue _ = Left "not a JSON array"

 

whenRight :: (b -> c) -> Either a b -> Either a c

whenRight _ (Left err) = Left err

whenRight f (Right a) = Right (f a)

 

mapEithers :: (a -> Either b c) -> [a] -> Either b [c]

mapEithers f (x:xs) = case mapEithers f xs of

                          Left err -> Left err

                          Right ys -> case f x of

                                         Left err -> Left err

                                         Right y -> Right (y:ys)

mapEithers _ _ = Right []

 

 

instance (JSON a) => JSON (JObj a) where

    toJValue = JObject . JObj . map (second toJValue) . fromJObj

    fromJValue (JObject (JObj o)) = whenRight JObj (mapEithers unwrap o)

        where unwrap (k,v) = whenRight ((,) k) (fromJValue v)

    fromJValue _ = Left "not a JSON object"


 

The Dreaded Monomorphism Restriction

 

myShow = show  -- 出错?

 

-- ok ?

myShow2 value = show value

myShow3 :: (Show a) => a -> String

myShow3 = show

 

real world haskell english real world haskell english version 立即下载

相关推荐

haskell the craft of functional programming

haskell the craft of functional programming epub 格式 英文

Haskell小例子

class MyEq a where myeq ::a->a->Bool myeq x y = not( mynoteq x y ) mynoteq ::a->a->Bool mynoteq x y = not (myeq x y) class BasicEq3 a where isEqual3 :: a -> a -> Bool isEq

daaoke的专栏 1778

Haskell函数式编程入门 张淞

Haskell函数式编程入门

Haskell语言的后端开发

Haskell是一种强大的语言,适合用于后端开发。它的纯函数式编程特性、强静态类型系统以及并发支持,使得开发高性能、高可靠性的后端服务成为可能。随着Haskell生态系统的不断发展,越来越多的开发者开始关注这门语言,希望能够在后端开发中利用其优势。尽管Haskell也面临一些挑战,如学习曲线较陡和社区相对较小,但这些并不影响其在后端开发中的应用前景。相信随着更多案例的出现,Haskell将会在后端开发领域扮演越来越重要的角色。

2501_91195826的博客 1053

从零构建:毫米波雷达生命信号检测系统的Matlab仿真全流程解析

本文详细解析了毫米波雷达生命信号检测系统的Matlab仿真全流程,涵盖原理、信号处理链路设计及算法优化策略。通过FMCW雷达技术,实现非接触式呼吸心跳信号检测,结合Matlab代码示例展示距离FFT、相位提取与信号分离等关键步骤,为医疗监护和智能家居应用提供实用指南。

weixin_29303701的博客 357

Linux系统centos7安装网卡驱动

有时候我们装完Centos或Ubuntu系统会发现没有网卡信息,说明网卡驱动不配置,所以我们要重新安装。 首先去服务器主板官网下载网卡驱动,注意32位和64位。 先查看网卡型号 lspci | grep -i ethernet 我的网卡型号是 00:1f.6 Ethernet controller: Intel Corporation Device 0d55。 网上一找,压根没找到这型号的网卡,别说驱动了。怀着试一试的心态,就安装i219-v系的网卡驱动,还别说,成功了。 针对i21...

wshc18的博客 2万+

Haskell语言的函数实现

本文深入探讨了Haskell语言中的函数实现,从基本的函数定义到高阶函数、部分应用、递归及懒加载特性,展示了Haskell的强大功能和优雅的表达方式。通过结合具体例子,我们看到了函数式编程如何使代码更加简洁、优雅。掌握Haskell中的函数实现对于编写高效、可维护的代码至关重要,期望这些内容能为读者在Haskell的学习和应用中提供帮助。Haskell的函数式编程理念不仅在学术界广泛关注,在业界也被越来越多的高性能计算和数据处理应用所采纳。

2501_90384062的博客 414

汽车ECU开发必看:AUTOSAR存储管理模块NvM的5个实战技巧

本文聚焦汽车ECU开发中AUTOSAR存储管理模块NvM的实战应用,分享了五个源自量产项目的核心技巧。内容涵盖Class 3配置的精细调优、稳健冗余策略的构建、读写性能的毫秒级优化、典型工程问题的解决方案以及高效的集成测试方法,旨在帮助开发者规避常见陷阱,实现可靠、高效的存储方案。

weixin_29192211的博客 275

lambda表达式案例(持续更新)

1、收集数字结果 (1)统计Map里某种value的出现次数(总和/平均数/最大值等均可) IntSummaryStatistics summary = cStatusMap.entrySet().stream().filter(x -> x.getValue() == Status.OK).collect(Collectors.summarizingInt(Map.Entry::getV

Horizon_LGMH的博客 1821

统信UOS下获取root权限的两种姿势:图形化开启开发者模式 vs 命令行直接提权

本文详细解析了统信UOS下获取root权限的两种方法:通过图形界面永久开启开发者模式和使用命令行临时提权。开发者模式适合系统级开发,提供完整root权限但降低安全性;临时提权则更灵活,适合日常管理任务。文章还对比了两种方案的优缺点,帮助用户根据需求选择最佳权限管理策略。

weixin_30266885的博客 515

【5】GD32H7xx CAN发送及FIFO接收

GD32H7xx CAN收发调试记录,包含源码

madao1234的博客 1818

Haskell语言学习笔记(72)Free Monad

安装 free 包 $ cabal install free Installed free-5.0.2 Free Monad data Free f a = Pure a | Free (f (Free f a)) instance Functor f =&gt; Functor (Free f) where fmap f = go where go (Pure a...

zwvista的专栏 567

基于Python的CT骨料图像分割与STL批量导出完整指南

本文介绍了一套完整的Python解决方案,用于CT骨料图像的分割与STL导出。针对CT图像中颗粒粘连、噪声伪影等技术难点,提出基于分水岭算法的分割策略,结合距离变换与标记控制实现颗粒分离。内容包括环境配置、数据读取与预处理、Otsu阈值分割、分水岭算法实现、表面提取与STL导出等关键步骤。教程提供详细代码及解释,帮助读者从CT体数据出发,最终生成每个颗粒的三维网格文件,便于后续定量分析和数值模拟。

huanghm88的专栏 237

Haskell之Yesod开发–简单网站开发(一)

Haskell Yesod web

daaoke的专栏 1232

安装keil软件时安装不了芯片包怎么回事?芯片包安装路径放在Keill里的packs下面,弹框提示报错:Errors retumned from cpackget...如何解决?

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 2207

企业合规审查系统开发实战:基于知识图谱与深度学习的智能引擎构建(附完整Python代码)

动态合规监测:实时追踪法规变化并更新知识库智能合约审计:区块链智能合约的自动合规检查跨域知识融合:整合财务、法律、业务多维度数据可解释性增强:基于Attention机制生成合规审查依据。

理论都是虚的,代码才是王道。 456

haskell Standard list functions(列表的标准库函数)

-- Standard list functions module PreludeList (     map, (++), filter, concat, concatMap,      head, last, tail, init, null, length, (!!),      foldl, foldl1, scanl, scanl1, foldr, foldr1, scanr

crazyhacking的专栏 3713

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

HASKELL起步入门教程

函数式编程HASKELL起步入门教程  Haskell作为一门纯函数语言,它有以下特点:Haskell强表达能力可以提高软件的生产力小语言核心提供了很大的灵活性代码可以很简洁,提高开发速度从编译和解释两种语言中都能得到两全其美的好处Haskell使代码更容易理解和维护可以深入复杂的库和理解代码是做 什么Haskell可以提高系统的鲁棒性强类型捕获在编译时许多的错误函数代码允许更好的测试方法没有变化...

丿灬安之若死 5310

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Haskell:String和ByteString互相转换代码

<br /><br />toBS :: String -> BS.ByteString<br />toBS = BS.pack . map (fromIntegral . fromEnum)<br /> <br />fromBS :: BS.ByteString -> String<br />fromBS = map (toEnum . fromIntegral) . BS.unpack

mjk的专栏 7161

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Haskell 学习笔记-20:除法( Division, UVa 725)

看了几本 Haskell 教程,我觉得这些书都没有站在程序员的角度安排内容顺序。其实对于大部分程序员来讲,脑子里就是 C 语言的基本套路。因此, Haskell 的教程应该从 C 语言相近的方式开始课程。等我用 Haskell 开发一个应用系统后,考虑编写一本真正的入门教程。今天发一段 ACM 竞赛题的 Haskell 程序。 除法( Division, UVa 725) 输入正整数 n, 按从小...

程序猿视角 2255

优美的函数式语言Haskell

教程 Yet Another Haskell Tutorial (English 简体中文) Haskell-Tutorial (English) A Gentle Introduction to Haskell (English) Haskell Kurs (德语) [编辑]课程 Programming in Haskell (English) Functional program...

weixin_33915554的博客 196

(转)Haskell与范畴论

Haskell与范畴论 http://www.yi-programmer.com/blog/2010-04-06_haskell_and_category_translate.html 用haskell的概念解释范畴论。翻译自 wikibook : http://en.wikibooks.org/wiki/Haskell/Category_theory 目录 范畴论简介 范...

yntcsb的专栏 687

Haskell --- List Comprehension List集合操作

// 生成x在区间内的2倍值 ghci&gt; [x*2 | x &lt;- [1..10]]   [2,4,6,8,10,12,14,16,18,20] // 生成x在区间内的2倍值,并且大雨12的数 [x * 2 | x &lt;- [1..10], x * 2 &gt;= 12]    // 生成50到100之间,对7做除法余数是3的数  ghci&gt; [ x | x &lt;- [...

杨鑫newlife的专栏 2239

我的第一个Haskell程序

今天下午写了一个Haskell的hello world,结果不能运行: [code="Haskell"] module test(main) where import System.IO data Shape = Circle Float Float Float | Rectangle Float Float Float Float surface :: Shape -> Float...

messi 477

「学习总结-Haskell-4」Haskell数据类型

Haskell 数据类型 Table of Contents 1 Haskell 基本知识2 Haskell 重要数据结构-List3 Haskell 常用数据结构4 Haskell 类型 4.1 数据类型的查看与表示 4.1.1 查看数据类型4.1.2 函数类型的表示4.1.3 基本数据类型 4.2 类型类(Type class) 4.2...

439
上一篇: Real World Haskell - Chapter 5. Writing a Library: Working with JSON
下一篇: Real World Haskell - Chapter 7. I/O
蓝色歌谣
博客等级 码龄19年 55粉丝 126原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值